/* tc-xtensa.c -- Assemble Xtensa instructions.
- Copyright 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
#include <string.h>
#include <limits.h>
static enum debug_info_type xt_saved_debug_type = DEBUG_NONE;
/* Some functions are only valid in the front end. This variable
- allows us to assert that we haven't crossed over into the
+ allows us to assert that we haven't crossed over into the
back end. */
static bfd_boolean past_xtensa_end = FALSE;
int num_formats;
/* A number describing how restrictive the issue is for this
opcode. For example, an opcode that fits lots of different
- formats has a high freedom, as does an opcode that fits
+ formats has a high freedom, as does an opcode that fits
only one format but many slots in that format. The most
- restrictive is the opcode that fits only one slot in one
+ restrictive is the opcode that fits only one slot in one
format. */
int issuef;
- /* The single format (i.e., if the op can live in a bundle by itself),
- narrowest format, and widest format the op can be bundled in
- and their sizes: */
- xtensa_format single;
xtensa_format narrowest;
- xtensa_format widest;
char narrowest_size;
- char widest_size;
- char single_size;
+ char narrowest_slot;
/* formats is a bitfield with the Nth bit set
if the opcode fits in the Nth xtensa_format. */
static void xtensa_begin_directive (int);
static void xtensa_end_directive (int);
-static void xtensa_dwarf2_directive_loc (int);
static void xtensa_literal_prefix (char const *, int);
static void xtensa_literal_position (int);
static void xtensa_literal_pseudo (int);
extern bfd_boolean opcode_fits_format_slot (xtensa_opcode, xtensa_format, int);
static int xg_get_single_size (xtensa_opcode);
static xtensa_format xg_get_single_format (xtensa_opcode);
+static int xg_get_single_slot (xtensa_opcode);
/* TInsn and IStack functions. */
bfd_boolean expr_is_register (const expressionS *);
offsetT get_expr_register (const expressionS *);
void set_expr_symbol_offset (expressionS *, symbolS *, offsetT);
-static void set_expr_symbol_offset_diff
- (expressionS *, symbolS *, symbolS *, offsetT);
bfd_boolean expr_is_equal (expressionS *, expressionS *);
static void copy_expr (expressionS *, const expressionS *);
/* -Qy, -Qn: SVR4 arguments controlling whether a .comment section
should be emitted or not. FIXME: Not implemented. */
return 1;
-
+
case option_prefer_l32r:
if (prefer_const16)
as_fatal (_("prefer-l32r conflicts with prefer-const16"));
prefer_const16 = 1;
return 1;
- case option_target_hardware:
+ case option_target_hardware:
{
int earliest, latest = 0;
if (*arg == 0 || *arg == '-')
}
-/* The "loops_ok" argument is provided to allow ignoring labels that
- define loop ends. This fixes a bug where the NOPs to align a
+/* 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
{ "short", xtensa_elf_cons, 2 },
{ "begin", xtensa_begin_directive, 0 },
{ "end", xtensa_end_directive, 0 },
- { "loc", xtensa_dwarf2_directive_loc, 0 },
{ "literal", xtensa_literal_pseudo, 0 },
{ "frequency", xtensa_frequency_pseudo, 0 },
{ NULL, 0, 0 },
/* This code is a hack to make .begin [no-][generics|relax] exactly
equivalent to .begin [no-]transform. We should remove it when
we stop accepting those options. */
-
+
if (strncmp (input_line_pointer, "generics", strlen ("generics")) == 0)
{
as_warn (_("[no-]generics is deprecated; use [no-]transform instead"));
{
as_warn (_("[no-]relax is deprecated; use [no-]transform instead"));
directive_string = "transform";
- }
+ }
else
directive_string = input_line_pointer;
break;
case directive_literal_prefix:
- /* Have to flush pending output because a movi relaxed to an l32r
+ /* Have to flush pending output because a movi relaxed to an l32r
might produce a literal. */
md_flush_pending_output ();
/* Check to see if the current fragment is a literal
s = (lit_state *) state;
assert (s);
- if (use_literal_section)
- default_lit_sections = *s;
+ default_lit_sections = *s;
/* free the state storage */
free (s);
}
-/* Wrap dwarf2 functions so that we correctly support the .loc directive. */
-
-static bfd_boolean xtensa_loc_directive_seen = FALSE;
-
-static void
-xtensa_dwarf2_directive_loc (int x)
-{
- xtensa_loc_directive_seen = TRUE;
- dwarf2_directive_loc (x);
-}
-
-
-static void
-xtensa_dwarf2_emit_insn (int size, struct dwarf2_line_info *loc)
-{
- if (debug_type != DEBUG_DWARF2 && ! xtensa_loc_directive_seen)
- return;
- xtensa_loc_directive_seen = FALSE;
- dwarf2_gen_line_info (frag_now_fix () - size, loc);
-}
-
-
/* Place an aligned literal fragment at the current location. */
static void
input_line_pointer = arg_end;
num_args += 1;
- saw_comma = FALSE;
+ saw_comma = FALSE;
saw_colon = FALSE;
- saw_arg = TRUE;
+ saw_arg = TRUE;
break;
}
}
else if (saw_colon)
as_bad (_("extra colon"));
else if (!saw_arg)
- as_bad (_("missing argument"));
+ as_bad (_("missing argument"));
else
as_bad (_("missing comma or colon"));
input_line_pointer = old_input_line_pointer;
goto err;
insn->ntok = tok - insn->tok;
- had_error = FALSE;
+ had_error = FALSE;
err:
input_line_pointer = old_input_line_pointer;
if (xtensa_operand_is_PCrelative (xtensa_default_isa, opcode, operand)
== 1)
as_bad_where ((char *) file, line,
- _("operand %u is out of range for '%s'"), value,
- xtensa_opcode_name (xtensa_default_isa, opcode));
+ _("operand %d of '%s' has out of range value '%u'"),
+ operand + 1,
+ xtensa_opcode_name (xtensa_default_isa, opcode),
+ value);
else
as_bad_where ((char *) file, line,
- _("operand %u is invalid for '%s'"), value,
- xtensa_opcode_name (xtensa_default_isa, opcode));
+ _("operand %d of '%s' has invalid value '%u'"),
+ operand + 1,
+ xtensa_opcode_name (xtensa_default_isa, opcode),
+ value);
return;
}
NARROW_ONLY is true, then only consider relaxations that widen a narrow
instruction, i.e., ignore relaxations that convert to an instruction of
equal size. In some contexts where this function is used, only
- a single widening is allowed and the NARROW_ONLY argument is used to
+ a single widening is allowed and the NARROW_ONLY argument is used to
exclude cases like ADDI being "widened" to an ADDMI, which may
later be relaxed to an ADDMI/ADDI pair. */
{
target += stretch;
}
-
+
new_offset = target;
xtensa_operand_do_reloc (isa, insn->opcode, i, &new_offset, pc);
if (xg_check_operand (new_offset, insn->opcode, i))
symbolS *sym;
memset (targ, 0, sizeof (TInsn));
- targ->loc = insn->loc;
+ targ->linenum = insn->linenum;
switch (bi->typ)
{
case INSTR_INSTR:
/* Walk through all of the single instruction expansions. */
while (xg_is_single_relaxable_insn (¤t_insn, &single_target, FALSE))
{
+ steps_taken++;
if (xg_symbolic_immeds_fit (&single_target, pc_seg, pc_frag, pc_offset,
stretch))
{
- steps_taken++;
if (steps_taken >= min_steps)
{
istack_push (istack, &single_target);
if (target_frag == NULL)
return FALSE;
- if (is_next_frag_target (fragP->fr_next, target_frag)
+ if (is_next_frag_target (fragP->fr_next, target_frag)
&& S_GET_VALUE (sym) == target_frag->fr_address)
return TRUE;
new_insn->insn_type = ITYPE_INSN;
new_insn->opcode = instr_spec->opcode;
new_insn->is_specific_opcode = FALSE;
- new_insn->loc = old_insn->loc;
+ new_insn->linenum = old_insn->linenum;
break;
case INSTR_LITERAL_DEF:
new_insn->insn_type = ITYPE_LITERAL;
new_insn->opcode = XTENSA_UNDEFINED;
new_insn->is_specific_opcode = FALSE;
- new_insn->loc = old_insn->loc;
+ new_insn->linenum = old_insn->linenum;
break;
case INSTR_LABEL_DEF:
as_bad (_("INSTR_LABEL_DEF not supported yet"));
if (size > litsize)
{
/* This happens when someone writes a "movi a2, big_number". */
- as_bad_where (frag_now->fr_file, frag_now->fr_line,
+ as_bad_where (frag_now->fr_file, frag_now->fr_line,
_("invalid immediate"));
xtensa_restore_emit_state (&state);
return NULL;
if (opnum != get_relaxable_immed (opcode))
{
as_bad (_("invalid relocation for operand %i of '%s'"),
- opnum, xtensa_opcode_name (xtensa_default_isa, opcode));
+ opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
return FALSE;
}
if (expr->X_op == O_lo16 || expr->X_op == O_hi16)
{
as_bad (_("invalid expression for operand %i of '%s'"),
- opnum, xtensa_opcode_name (xtensa_default_isa, opcode));
+ opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
return FALSE;
}
the_fix->tc_fix_data.X_add_symbol = expr->X_add_symbol;
the_fix->tc_fix_data.X_add_number = expr->X_add_number;
the_fix->tc_fix_data.slot = slot;
-
+
return TRUE;
}
static bfd_boolean
xg_emit_insn_to_buf (TInsn *tinsn,
- xtensa_format fmt,
char *buf,
fragS *fragP,
offsetT offset,
static xtensa_insnbuf insnbuf = NULL;
bfd_boolean has_symbolic_immed = FALSE;
bfd_boolean ok = TRUE;
+
if (!insnbuf)
insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
if (has_symbolic_immed && build_fix)
{
/* Add a fixup. */
+ xtensa_format fmt = xg_get_single_format (tinsn->opcode);
+ int slot = xg_get_single_slot (tinsn->opcode);
int opnum = get_relaxable_immed (tinsn->opcode);
expressionS *exp = &tinsn->tok[opnum];
- if (!xg_add_opcode_fix (tinsn, opnum, fmt, 0, exp, fragP, offset))
+ if (!xg_add_opcode_fix (tinsn, opnum, fmt, slot, exp, fragP, offset))
ok = FALSE;
}
fragP->tc_frag_data.is_insn = TRUE;
|| opcode == xtensa_waiti_opcode
|| opcode == xtensa_rsr_lcount_opcode)
return TRUE;
-
+
return FALSE;
}
{
fragS *next_fragP = fragP->fr_next;
- /* Sometimes an empty will end up here due storage allocation issues.
+ /* Sometimes an empty will end up here due storage allocation issues.
So we have to skip until we find something legit. */
while (next_fragP && next_fragP->fr_fix == 0)
next_fragP = next_fragP->fr_next;
static xtensa_insnbuf insnbuf = NULL;
xtensa_isa isa = xtensa_default_isa;
xtensa_format fmt;
- int fmt_size;
+ int fmt_size;
if (!insnbuf)
insnbuf = xtensa_insnbuf_alloc (isa);
if (fragP->fr_opcode != fragP->fr_literal)
return fmt_size;
- /* If during relaxation we have to pull an instruction out of a
+ /* If during relaxation we have to pull an instruction out of a
multi-slot instruction, we will return the more conservative
number. This works because alignment on bigger instructions
is more restrictive than alignment on smaller instructions.
if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP1
|| fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP2)
return 3;
-
+
if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
return 2 + fragP->tc_frag_data.text_expansion[0];
static bfd_boolean
next_frag_is_loop_target (const fragS *fragP)
{
- /* Sometimes an empty will end up here due storage allocation issues.
+ /* Sometimes an empty will end up here due storage allocation issues.
So we have to skip until we find something legit. */
for (fragP = fragP->fr_next; fragP; fragP = fragP->fr_next)
{
fragP->tc_frag_data.is_no_density = TRUE;
/* This function is called from subsegs_finish, which is called
- after xtensa_end, so we can't use "use_transform" or
+ after xtensa_end, so we can't use "use_transform" or
"use_schedule" here. */
if (!directive_state[directive_transform])
fragP->tc_frag_data.is_no_transform = TRUE;
flagword flags = bfd_get_section_flags (abfd, sec);
segment_info_type *seginfo = seg_info (sec);
fragS *frag = seginfo->frchainP->frch_root;
-
+
if (flags & SEC_CODE)
- {
+ {
xtensa_isa isa = xtensa_default_isa;
xtensa_insnbuf insnbuf = xtensa_insnbuf_alloc (isa);
while (frag != NULL)
segment_info_type *seginfo = seg_info (sec);
fragS *frag = seginfo->frchainP->frch_root;
xtensa_isa isa = xtensa_default_isa;
-
+
if (flags & SEC_CODE)
- {
+ {
xtensa_insnbuf insnbuf = xtensa_insnbuf_alloc (isa);
while (frag != NULL)
{
void
xtensa_frob_label (symbolS *sym)
{
- float freq = get_subseg_target_freq (now_seg, now_subseg);
+ float freq;
+
+ if (cur_vinsn.inside_bundle)
+ {
+ as_bad (_("labels are not valid inside bundles"));
+ return;
+ }
+
+ freq = get_subseg_target_freq (now_seg, now_subseg);
/* Since the label was already attached to a frag associated with the
previous basic block, it now needs to be reset to the current frag. */
xtensa_set_frag_assembly_state (frag_now);
xtensa_move_labels (frag_now, 0, TRUE);
- }
+ }
/* No target aligning in the absolute section. */
if (now_seg != absolute_section
/* 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;
+
+ dwarf2_emit_label (sym);
}
md_assemble (char *str)
{
xtensa_isa isa = xtensa_default_isa;
- char *opname;
+ char *opname, *file_name;
unsigned opnamelen;
bfd_boolean has_underbar = FALSE;
char *arg_strings[MAX_INSN_ARGS];
return;
}
- dwarf2_where (&orig_insn.loc);
-
+ /* A FLIX bundle may be spread across multiple input lines. We want to
+ report the first such line in the debug information. Record the line
+ number for each TInsn (assume the file name doesn't change), so the
+ first line can be found later. */
+ as_where (&file_name, &orig_insn.linenum);
+
xg_add_branch_and_loop_targets (&orig_insn);
- /* Special-case for "entry" instruction. */
- if (orig_insn.opcode == xtensa_entry_opcode)
+ /* Check that immediate value for ENTRY is >= 16. */
+ if (orig_insn.opcode == xtensa_entry_opcode && orig_insn.ntok >= 3)
{
- /* Check that the third opcode (#2) is >= 16. */
- if (orig_insn.ntok >= 3)
- {
- expressionS *exp = &orig_insn.tok[2];
- switch (exp->X_op)
- {
- case O_constant:
- if (exp->X_add_number < 16)
- as_warn (_("entry instruction with stack decrement < 16"));
- break;
-
- default:
- as_warn (_("entry instruction with non-constant decrement"));
- }
- }
+ expressionS *exp = &orig_insn.tok[2];
+ if (exp->X_op == O_constant && exp->X_add_number < 16)
+ as_warn (_("entry instruction with stack decrement < 16"));
}
/* Finish it off:
int count;
count = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
if (count != 0)
- as_bad_where (fragP->fr_file, fragP->fr_line,
+ as_bad_where (fragP->fr_file, fragP->fr_line,
_("unaligned entry instruction"));
}
}
void
-md_apply_fix3 (fixS *fixP, valueT *valP, segT seg)
+md_apply_fix (fixS *fixP, valueT *valP, segT seg)
{
char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
- valueT val;
+ valueT val = 0;
+
+ /* Subtracted symbols are only allowed for a few relocation types, and
+ unless linkrelax is enabled, they should not make it to this point. */
+ if (fixP->fx_subsy && !(linkrelax && (fixP->fx_r_type == BFD_RELOC_32
+ || fixP->fx_r_type == BFD_RELOC_16
+ || fixP->fx_r_type == BFD_RELOC_8)))
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
switch (fixP->fx_r_type)
{
case BFD_RELOC_32:
case BFD_RELOC_16:
case BFD_RELOC_8:
- if (linkrelax && fixP->fx_subsy)
+ if (fixP->fx_subsy)
{
switch (fixP->fx_r_type)
{
val = *valP;
fixP->fx_done = 1;
}
- else
- break;
+ /* fall through */
+
+ case BFD_RELOC_XTENSA_PLT:
md_number_to_chars (fixpos, val, fixP->fx_size);
fixP->fx_no_overflow = 0; /* Use the standard overflow check. */
break;
}
break;
- case BFD_RELOC_XTENSA_PLT:
case BFD_RELOC_XTENSA_ASM_EXPAND:
case BFD_RELOC_XTENSA_SLOT0_ALT:
case BFD_RELOC_XTENSA_SLOT1_ALT:
\f
/* Checks for resource conflicts between instructions. */
-/* The func unit stuff could be implemented as bit-vectors rather
- than the iterative approach here. If it ends up being too
+/* The func unit stuff could be implemented as bit-vectors rather
+ than the iterative approach here. If it ends up being too
slow, we will switch it. */
-resource_table *
+resource_table *
new_resource_table (void *data,
int cycles,
int nu,
rt->opcode_unit_use = ouuf;
rt->opcode_unit_stage = ousf;
- rt->units = (char **) xcalloc (cycles, sizeof (char *));
+ rt->units = (unsigned char **) xcalloc (cycles, sizeof (unsigned char *));
for (i = 0; i < cycles; i++)
- rt->units[i] = (char *) xcalloc (nu, sizeof (char));
+ rt->units[i] = (unsigned char *) xcalloc (nu, sizeof (unsigned char));
return rt;
}
-void
+void
clear_resource_table (resource_table *rt)
{
int i, j;
/* We never shrink it, just fake it into thinking so. */
-void
+void
resize_resource_table (resource_table *rt, int cycles)
{
int i, old_cycles;
old_cycles = rt->allocated_cycles;
rt->allocated_cycles = cycles;
- rt->units = xrealloc (rt->units, sizeof (char *) * rt->allocated_cycles);
+ rt->units = xrealloc (rt->units,
+ rt->allocated_cycles * sizeof (unsigned char *));
for (i = 0; i < old_cycles; i++)
- rt->units[i] = xrealloc (rt->units[i], sizeof (char) * rt->num_units);
+ rt->units[i] = xrealloc (rt->units[i],
+ rt->num_units * sizeof (unsigned char));
for (i = old_cycles; i < cycles; i++)
- rt->units[i] = xcalloc (rt->num_units, sizeof (char));
+ rt->units[i] = xcalloc (rt->num_units, sizeof (unsigned char));
}
-bfd_boolean
+bfd_boolean
resources_available (resource_table *rt, xtensa_opcode opcode, int cycle)
{
int i;
int uses = (rt->opcode_num_units) (rt->data, opcode);
- for (i = 0; i < uses; i++)
+ for (i = 0; i < uses; i++)
{
xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i);
int stage = (rt->opcode_unit_stage) (rt->data, opcode, i);
}
return TRUE;
}
-
-void
+
+void
reserve_resources (resource_table *rt, xtensa_opcode opcode, int cycle)
{
int i;
int uses = (rt->opcode_num_units) (rt->data, opcode);
- for (i = 0; i < uses; i++)
+ for (i = 0; i < uses; i++)
{
xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i);
int stage = (rt->opcode_unit_stage) (rt->data, opcode, i);
- /* Note that this allows resources to be oversubscribed. That's
- essential to the way the optional scheduler works.
+ /* Note that this allows resources to be oversubscribed. That's
+ essential to the way the optional scheduler works.
resources_available reports when a resource is over-subscribed,
so it's easy to tell. */
rt->units[stage + cycle][unit]++;
}
-void
+void
release_resources (resource_table *rt, xtensa_opcode opcode, int cycle)
{
int i;
int uses = (rt->opcode_num_units) (rt->data, opcode);
- for (i = 0; i < uses; i++)
+ for (i = 0; i < uses; i++)
{
xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i);
int stage = (rt->opcode_unit_stage) (rt->data, opcode, i);
+ assert (rt->units[stage + cycle][unit] > 0);
rt->units[stage + cycle][unit]--;
- assert (rt->units[stage + cycle][unit] >= 0);
}
}
-
+
/* Wrapper functions make parameterized resource reservation
more convenient. */
-int
+int
opcode_funcUnit_use_unit (void *data, xtensa_opcode opcode, int idx)
{
xtensa_funcUnit_use *use = xtensa_opcode_funcUnit_use (data, opcode, idx);
- return use->unit;
+ return use->unit;
}
-int
+int
opcode_funcUnit_use_stage (void *data, xtensa_opcode opcode, int idx)
{
xtensa_funcUnit_use *use = xtensa_opcode_funcUnit_use (data, opcode, idx);
/* Note that this function does not check issue constraints, but
solely whether the hardware is available to execute the given
- instructions together. It also doesn't check if the tinsns
+ instructions together. It also doesn't check if the tinsns
write the same state, or access the same tieports. That is
checked by check_t1_t2_reads_and_writes. */
if (vinsn->num_slots == 1)
return FALSE;
- if (rt == NULL)
+ if (rt == NULL)
{
xtensa_isa isa = xtensa_default_isa;
rt = new_resource_table
static bfd_boolean find_vinsn_conflicts (vliw_insn *);
static xtensa_format xg_find_narrowest_format (vliw_insn *);
-static void bundle_single_op (TInsn *);
static void xg_assemble_vliw_tokens (vliw_insn *);
return;
}
- if (resources_conflict (vinsn))
+ if (resources_conflict (vinsn))
{
as_where (&file_name, &line);
as_bad_where (file_name, line, _("illegal resource usage in bundle"));
}
else
{
- bundle_single_op (&slotstack.insn[slotstack.ninsn - 1]);
+ emit_single_op (&slotstack.insn[slotstack.ninsn - 1]);
if (vinsn->format == XTENSA_UNDEFINED)
vinsn->slots[i].opcode = xtensa_nop_opcode;
else
- vinsn->slots[i].opcode
+ vinsn->slots[i].opcode
= xtensa_format_slot_nop_opcode (xtensa_default_isa,
vinsn->format, i);
}
/* Now check resource conflicts on the modified bundle. */
- if (resources_conflict (vinsn))
+ if (resources_conflict (vinsn))
{
as_where (&file_name, &line);
as_bad_where (file_name, line, _("illegal resource usage in bundle"));
xtensa_opcode_name (isa, op2->opcode), j);
return TRUE;
case 'e':
- as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same queue"),
+ as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same port"),
xtensa_opcode_name (isa, op1->opcode), i,
xtensa_opcode_name (isa, op2->opcode), j);
return TRUE;
case 'f':
- as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) both have volatile queue accesses"),
+ as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) both have volatile port accesses"),
xtensa_opcode_name (isa, op1->opcode), i,
xtensa_opcode_name (isa, op2->opcode), j);
return TRUE;
case A: t1 reads a register t2 writes (an antidependency within a bundle)
case B: no relationship between what is read and written (both could
read the same reg though)
- case C: t1 writes a register t2 writes (a register conflict within a
+ case C: t1 writes a register t2 writes (a register conflict within a
bundle)
case D: t1 writes a state that t2 also writes
case E: t1 writes a tie queue that t2 also writes
{
xtensa_state t1_so = xtensa_stateOperand_state (isa, t1->opcode, i);
t1_inout = xtensa_stateOperand_inout (isa, t1->opcode, i);
- if (t1_so != t2_so)
+ if (t1_so != t2_so)
continue;
if (t2_inout == 'i' && (t1_inout == 'm' || t1_inout == 'o'))
conflict = 'a';
continue;
}
-
+
if (t1_inout == 'i' && (t2_inout == 'm' || t2_inout == 'o'))
{
conflict = 'a';
continue;
}
-
+
if (t1_inout != 'i' && t2_inout != 'i')
return 'd';
- }
+ }
}
/* Check tieports. */
t1_interfaces = xtensa_opcode_num_interfaceOperands (isa, t1->opcode);
t2_interfaces = xtensa_opcode_num_interfaceOperands (isa, t2->opcode);
- for (j = 0; j < t2_interfaces; j++)
+ for (j = 0; j < t2_interfaces; j++)
{
xtensa_interface t2_int
= xtensa_interfaceOperand_interface (isa, t2->opcode, j);
int t2_class = xtensa_interface_class_id (isa, t2_int);
- t2_inout = xtensa_interface_inout (isa, j);
+ t2_inout = xtensa_interface_inout (isa, t2_int);
if (xtensa_interface_has_side_effect (isa, t2_int) == 1)
t2_volatile = TRUE;
= xtensa_interfaceOperand_interface (isa, t1->opcode, j);
int t1_class = xtensa_interface_class_id (isa, t1_int);
- t1_inout = xtensa_interface_inout (isa, i);
+ t1_inout = xtensa_interface_inout (isa, t1_int);
if (xtensa_interface_has_side_effect (isa, t1_int) == 1)
t1_volatile = TRUE;
if (t1_volatile && t2_volatile && (t1_class == t2_class))
return 'f';
-
+
if (t1_int != t2_int)
continue;
-
+
if (t2_inout == 'i' && t1_inout == 'o')
{
conflict = 'a';
continue;
}
-
+
if (t1_inout == 'i' && t2_inout == 'o')
{
conflict = 'a';
continue;
}
-
+
if (t1_inout != 'i' && t2_inout != 'i')
return 'e';
}
}
-
+
return conflict;
}
vliw_insn v_copy = *vinsn;
xtensa_opcode nop_opcode = xtensa_nop_opcode;
+ if (vinsn->num_slots == 1)
+ return xg_get_single_format (vinsn->slots[0].opcode);
+
for (format = 0; format < xtensa_isa_num_formats (isa); format++)
{
v_copy = *vinsn;
each tinsn in the vinsn. */
static int
-relaxation_requirements (vliw_insn *vinsn)
+relaxation_requirements (vliw_insn *vinsn, bfd_boolean *pfinish_frag)
{
+ bfd_boolean finish_frag = FALSE;
int extra_space = 0;
int slot;
/* Difference in bytes between narrow and wide insns... */
extra_space += 1;
tinsn->subtype = RELAX_NARROW;
- tinsn->record_fix = TRUE;
- break;
- }
- else
- {
- tinsn->record_fix = FALSE;
- /* No extra_space needed. */
}
}
else
extra_space += 3; /* for the nop size */
tinsn->subtype = RELAX_ADD_NOP_IF_PRE_LOOP_END;
}
-
+
/* Need to assemble it with space for the relocation. */
if (xg_is_relaxable_insn (tinsn, 0)
&& !tinsn->is_specific_opcode)
int max_size = xg_get_max_insn_widen_size (tinsn->opcode);
int max_literal_size =
xg_get_max_insn_widen_literal_size (tinsn->opcode);
-
+
tinsn->literal_space = max_literal_size;
-
+
tinsn->subtype = RELAX_IMMED;
- tinsn->record_fix = FALSE;
extra_space += max_size;
}
else
{
- tinsn->record_fix = TRUE;
- /* No extra space needed. */
+ /* A fix record will be added for this instruction prior
+ to relaxation, so make it end the frag. */
+ finish_frag = TRUE;
}
}
}
+ *pfinish_frag = finish_frag;
return extra_space;
}
static void
-bundle_single_op (TInsn *orig_insn)
+bundle_tinsn (TInsn *tinsn, vliw_insn *vinsn)
{
xtensa_isa isa = xtensa_default_isa;
- vliw_insn v;
- int slot;
-
- xg_init_vinsn (&v);
- v.format = op_placement_table[orig_insn->opcode].narrowest;
- assert (v.format != XTENSA_UNDEFINED);
- v.num_slots = xtensa_format_num_slots (isa, v.format);
+ int slot, chosen_slot;
- for (slot = 0;
- !opcode_fits_format_slot (orig_insn->opcode, v.format, slot);
- slot++)
- {
- v.slots[slot].opcode =
- xtensa_format_slot_nop_opcode (isa, v.format, slot);
- v.slots[slot].ntok = 0;
- v.slots[slot].insn_type = ITYPE_INSN;
- }
+ vinsn->format = xg_get_single_format (tinsn->opcode);
+ assert (vinsn->format != XTENSA_UNDEFINED);
+ vinsn->num_slots = xtensa_format_num_slots (isa, vinsn->format);
- v.slots[slot] = *orig_insn;
- slot++;
-
- for ( ; slot < v.num_slots; slot++)
+ chosen_slot = xg_get_single_slot (tinsn->opcode);
+ for (slot = 0; slot < vinsn->num_slots; slot++)
{
- v.slots[slot].opcode =
- xtensa_format_slot_nop_opcode (isa, v.format, slot);
- v.slots[slot].ntok = 0;
- v.slots[slot].insn_type = ITYPE_INSN;
+ if (slot == chosen_slot)
+ vinsn->slots[slot] = *tinsn;
+ else
+ {
+ vinsn->slots[slot].opcode =
+ xtensa_format_slot_nop_opcode (isa, vinsn->format, slot);
+ vinsn->slots[slot].ntok = 0;
+ vinsn->slots[slot].insn_type = ITYPE_INSN;
+ }
}
-
- finish_vinsn (&v);
- xg_free_vinsn (&v);
}
istack_init (&istack);
/* Special-case for "movi aX, foo" which is guaranteed to need relaxing.
- Because the scheduling and bundling characteristics of movi and
- l32r or const16 are so different, we can do much better if we relax
+ Because the scheduling and bundling characteristics of movi and
+ l32r or const16 are so different, we can do much better if we relax
it prior to scheduling and bundling, rather than after. */
- if ((orig_insn->opcode == xtensa_movi_opcode
+ if ((orig_insn->opcode == xtensa_movi_opcode
|| orig_insn->opcode == xtensa_movi_n_opcode)
&& !cur_vinsn.inside_bundle
&& (orig_insn->tok[1].X_op == O_symbol
for (i = 0; i < istack.ninsn; i++)
{
TInsn *insn = &istack.insn[i];
- switch (insn->insn_type)
+ switch (insn->insn_type)
{
case ITYPE_LITERAL:
assert (lit_sym == NULL);
}
break;
case ITYPE_INSN:
- if (lit_sym)
- xg_resolve_literals (insn, lit_sym);
- if (label_sym)
- xg_resolve_labels (insn, label_sym);
- bundle_single_op (insn);
+ {
+ vliw_insn v;
+ if (lit_sym)
+ xg_resolve_literals (insn, lit_sym);
+ if (label_sym)
+ xg_resolve_labels (insn, label_sym);
+ xg_init_vinsn (&v);
+ bundle_tinsn (insn, &v);
+ finish_vinsn (&v);
+ xg_free_vinsn (&v);
+ }
break;
default:
assert (0);
static void
xg_assemble_vliw_tokens (vliw_insn *vinsn)
{
- bfd_boolean finish_frag = FALSE;
+ bfd_boolean finish_frag;
bfd_boolean is_jump = FALSE;
bfd_boolean is_branch = FALSE;
xtensa_isa isa = xtensa_default_isa;
int extra_space;
char *f = NULL;
int slot;
- struct dwarf2_line_info best_loc;
+ unsigned current_line, best_linenum;
+ char *current_file;
- best_loc.line = INT_MAX;
+ best_linenum = UINT_MAX;
if (generating_literals)
{
/* See if the instruction implies an aligned section. */
if (xtensa_opcode_is_loop (isa, vinsn->slots[i].opcode) == 1)
record_alignment (now_seg, 2);
-
+
/* Also determine the best line number for debug info. */
- best_loc = vinsn->slots[i].loc.line < best_loc.line
- ? vinsn->slots[i].loc : best_loc;
+ best_linenum = vinsn->slots[i].linenum < best_linenum
+ ? vinsn->slots[i].linenum : best_linenum;
}
/* Special cases for instructions that force an alignment... */
if (xtensa_opcode_is_loop (isa, vinsn->slots[0].opcode) == 1)
{
int max_fill;
-
+
xtensa_set_frag_assembly_state (frag_now);
frag_now->tc_frag_data.is_insn = TRUE;
-
+
max_fill = get_text_align_max_fill_size
(get_text_align_power (xtensa_fetch_width),
TRUE, frag_now->tc_frag_data.is_no_density);
frag_now->fr_offset,
NULL);
else
- frag_var (rs_machine_dependent, 0, 0,
+ frag_var (rs_machine_dependent, 0, 0,
RELAX_CHECK_ALIGN_NEXT_OPCODE, 0, 0, NULL);
xtensa_set_frag_assembly_state (frag_now);
-
+
xtensa_move_labels (frag_now, 0, FALSE);
}
insn_size = xtensa_format_length (isa, vinsn->format);
- extra_space = relaxation_requirements (vinsn);
+ extra_space = relaxation_requirements (vinsn, &finish_frag);
/* vinsn_to_insnbuf will produce the error. */
if (vinsn->format != XTENSA_UNDEFINED)
frag_now->tc_frag_data.is_insn = TRUE;
}
- vinsn_to_insnbuf (vinsn, f, frag_now, TRUE);
+ vinsn_to_insnbuf (vinsn, f, frag_now, FALSE);
if (vinsn->format == XTENSA_UNDEFINED)
return;
xtensa_insnbuf_to_chars (isa, vinsn->insnbuf, (unsigned char *) f, 0);
-
- xtensa_dwarf2_emit_insn (insn_size - extra_space, &best_loc);
+
+ /* Temporarily set the logical line number to the one we want to appear
+ in the debug information. */
+ as_where (¤t_file, ¤t_line);
+ new_logical_line (current_file, best_linenum);
+ dwarf2_emit_insn (insn_size + extra_space);
+ new_logical_line (current_file, current_line);
for (slot = 0; slot < vinsn->num_slots; slot++)
{
TInsn *tinsn = &vinsn->slots[slot];
frag_now->tc_frag_data.slot_subtypes[slot] = tinsn->subtype;
frag_now->tc_frag_data.slot_symbols[slot] = tinsn->symbol;
- frag_now->tc_frag_data.slot_sub_symbols[slot] = tinsn->sub_symbol;
frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset;
frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag;
if (tinsn->literal_space != 0)
if (xtensa_opcode_is_branch (isa, tinsn->opcode) == 1)
is_branch = TRUE;
- if (tinsn->subtype || tinsn->symbol || tinsn->record_fix
- || tinsn->offset || tinsn->literal_frag || is_jump || is_branch)
+ if (tinsn->subtype || tinsn->symbol || tinsn->offset
+ || tinsn->literal_frag || is_jump || is_branch)
finish_frag = TRUE;
}
&& fragP->fr_subtype == RELAX_SLOTS
&& fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
frag_wane (fragP);
- if (fragP->fr_type == rs_machine_dependent
+ if (fragP->fr_type == rs_machine_dependent
&& fragP->fr_subtype == RELAX_UNREACHABLE)
fragP->tc_frag_data.is_unreachable = TRUE;
}
&& fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED)
{
vliw_insn vinsn;
- const expressionS *expr;
- symbolS *symbolP;
vinsn_from_chars (&vinsn, fragP->fr_opcode);
tinsn_immed_from_frag (&vinsn.slots[0], fragP, 0);
- expr = &vinsn.slots[0].tok[1];
- symbolP = expr->X_add_symbol;
-
if (vinsn.num_slots == 1
&& xtensa_opcode_is_branch (xtensa_default_isa,
vinsn.slots[0].opcode)
{
fragP->fr_subtype = RELAX_SLOTS;
fragP->tc_frag_data.slot_subtypes[0] = RELAX_NARROW;
+ fragP->tc_frag_data.is_aligning_branch = 1;
}
}
}
{
const expressionS *expr = &tinsn->tok[1];
symbolS *symbolP = expr->X_add_symbol;
- fragS *target_frag = symbol_get_frag (symbolP);
offsetT max_distance = expr->X_add_number;
+ fragS *target_frag;
+
+ if (expr->X_op != O_symbol)
+ return FALSE;
+
+ target_frag = symbol_get_frag (symbolP);
+
max_distance += (S_GET_VALUE (symbolP) - target_frag->fr_address);
if (is_branch_jmp_to_next (tinsn, fragP))
return FALSE;
/* Of course, sometimes (mostly for toy test cases) a
zero-cost loop instruction is the last in a section. */
- if (targ_frag)
- {
- targ_frag->tc_frag_data.is_first_loop_insn = TRUE;
- if (fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE)
- frag_wane (fragP);
- }
+ if (targ_frag)
+ targ_frag->tc_frag_data.is_first_loop_insn = TRUE;
+ if (fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE)
+ frag_wane (fragP);
}
}
}
< REQUIRED_LOOP_DIVIDING_BYTES)
{
int length = 3;
-
+
if (fragP->fr_var < length)
as_fatal (_("fr_var %lu < length %d"),
(long) fragP->fr_var, length);
switch (fragP->fr_type)
{
case 0:
- /* Empty frags created by the obstack allocation scheme
+ /* Empty frags created by the obstack allocation scheme
end up with type 0. */
break;
case rs_fill:
alignment = (1 << align_pow);
assert (target_size > 0 && alignment >= (addressT) target_size);
-
+
if (!use_nops)
{
fill_limit = alignment;
the smallest number of bytes that need to be added to
ensure that the next fragment's FIRST instruction will fit
in a single word.
-
+
E.G., 2 bytes : 0, 1, 2 mod 4
3 bytes: 0, 1 mod 4
-
+
If the FIRST instruction MIGHT be relaxed,
assume that it will become a 3-byte instruction.
-
+
Note again here that LOOP instructions are not bundleable,
and this relaxation only applies to LOOP opcodes. */
-
+
int fill_size = 0;
int first_insn_size;
int loop_insn_size;
/* If it was 8, then we'll need a larger alignment for the section. */
align_power = get_text_align_power (first_insn_size);
record_alignment (now_seg, align_power);
-
+
fill_size = get_text_align_fill_size
(address + pre_opcode_bytes, align_power, first_insn_size, TRUE,
fragP->tc_frag_data.is_no_density);
}
/* Tell gas we need another relaxation pass. */
- if (! fragP->tc_frag_data.relax_seen)
+ if (! fragP->tc_frag_data.relax_seen)
{
fragP->tc_frag_data.relax_seen = TRUE;
*stretched_p = 1;
while (fragP)
{
/* Limit this to a small search. */
- if (*widens > 8)
+ if (*widens >= (int) xtensa_fetch_width)
{
*fragPP = fragP;
return 0;
return 0;
}
}
- else
+ else
{
/* Just punt if we don't know the type. */
*fragPP = fragP;
address = find_address_of_next_align_frag
(&fragP, &wide_nops, &narrow_nops, &num_widens, &paddable);
- if (address)
+ if (!address)
+ {
+ if (this_frag->tc_frag_data.is_aligning_branch)
+ this_frag->tc_frag_data.slot_subtypes[0] = RELAX_IMMED;
+ else
+ frag_wane (this_frag);
+ }
+ else
{
local_opt_diff = get_aligned_diff (fragP, address, &max_diff);
opt_diff = local_opt_diff;
assert (opt_diff >= 0);
assert (max_diff >= opt_diff);
- if (max_diff == 0)
+ if (max_diff == 0)
return 0;
if (fragP)
while (fragP && opt_diff < max_diff && address)
{
/* We only use these to determine if we can exit early
- because there will be plenty of ways to align future
+ because there will be plenty of ways to align future
align frags. */
int glob_widens = 0;
int dnn = 0;
(&fragP, &glob_widens, &dnn, &dw, &glob_pad);
/* If there is a padable portion, then skip. */
if (glob_pad || glob_widens >= (1 << branch_align_power (now_seg)))
- break;
+ address = 0;
- if (address)
+ if (address)
{
offsetT next_m_diff;
offsetT next_o_diff;
}
return 0;
}
- local_stretch_amount
+ local_stretch_amount
= bytes_to_stretch (this_frag, wide_nops, narrow_nops,
num_widens, local_opt_diff);
- global_stretch_amount
- = bytes_to_stretch (this_frag, wide_nops, narrow_nops,
+ global_stretch_amount
+ = bytes_to_stretch (this_frag, wide_nops, narrow_nops,
num_widens, opt_diff);
- /* If the condition below is true, then the frag couldn't
- stretch the correct amount for the global case, so we just
- optimize locally. We'll rely on the subsequent frags to get
+ /* If the condition below is true, then the frag couldn't
+ stretch the correct amount for the global case, so we just
+ optimize locally. We'll rely on the subsequent frags to get
the correct alignment in the global case. */
if (global_stretch_amount < local_stretch_amount)
stretch_amount = local_stretch_amount;
assert (desired_diff >= 0 && desired_diff < 8);
if (desired_diff == 0)
return 0;
-
+
assert (wide_nops > 0 || num_widens > 0);
/* Always prefer widening to NOP-filling. */
to align the target without widening this frag in any way. */
return 0;
}
-
+
if (bytes_short == 0)
{
/* Widen every narrow between here and the align target
else
return 1;
}
-
+
/* From here we will need at least one NOP to get an alignment.
However, we may not be able to align at all, in which case,
don't widen. */
if (!this_frag->tc_frag_data.is_no_density && narrow_nops == 1)
return 2; /* case 2 */
return 0;
- case 3:
+ case 3:
if (wide_nops > 1)
return 0;
else
case 5:
if (num_widens >= 2 && wide_nops == 1)
return 3; /* case 5a */
- /* We will need two nops. Are there enough nops
+ /* We will need two nops. Are there enough nops
between here and the align target? */
if (wide_nops < 2 || narrow_nops == 0)
return 0;
}
else
{
- /* We will need a NOP no matter what, but should we widen
+ /* We will need a NOP no matter what, but should we widen
this instruction to help?
This is a RELAX_FRAG_NARROW frag. */
bfd_boolean estimate_only)
{
TInsn tinsn;
- vliw_insn orig_vinsn;
int old_size;
bfd_boolean negatable_branch = FALSE;
bfd_boolean branch_jmp_to_next = FALSE;
assert (fragP->fr_opcode != NULL);
- xg_init_vinsn (&orig_vinsn);
- vinsn_from_chars (&orig_vinsn, fragP->fr_opcode);
- if (xtensa_format_num_slots (isa, fmt) > 1)
+ xg_clear_vinsn (&cur_vinsn);
+ vinsn_from_chars (&cur_vinsn, fragP->fr_opcode);
+ if (cur_vinsn.num_slots > 1)
wide_insn = TRUE;
- tinsn = orig_vinsn.slots[slot];
+ tinsn = cur_vinsn.slots[slot];
tinsn_immed_from_frag (&tinsn, fragP, slot);
if (estimate_only && xtensa_opcode_is_loop (isa, tinsn.opcode))
convert_frag_narrow (segT segP, fragS *fragP, xtensa_format fmt, int slot)
{
TInsn tinsn, single_target;
- xtensa_format single_fmt;
int size, old_size, diff;
offsetT frag_offset;
assert (slot == 0);
tinsn_from_chars (&tinsn, fragP->fr_opcode, 0);
- if (xtensa_opcode_is_branch (xtensa_default_isa, tinsn.opcode) == 1)
+ if (fragP->tc_frag_data.is_aligning_branch == 1)
{
assert (fragP->tc_frag_data.text_expansion[0] == 1
|| fragP->tc_frag_data.text_expansion[0] == 0);
}
size = xg_get_single_size (single_target.opcode);
- single_fmt = xg_get_single_format (single_target.opcode);
-
- xg_emit_insn_to_buf (&single_target, single_fmt, fragP->fr_opcode,
- fragP, frag_offset, TRUE);
+ xg_emit_insn_to_buf (&single_target, fragP->fr_opcode, fragP,
+ frag_offset, TRUE);
diff = size - old_size;
assert (diff >= 0);
bfd_boolean expanded = FALSE;
bfd_boolean branch_jmp_to_next = FALSE;
char *fr_opcode = fragP->fr_opcode;
- vliw_insn orig_vinsn;
xtensa_isa isa = xtensa_default_isa;
bfd_boolean wide_insn = FALSE;
int bytes;
assert (fr_opcode != NULL);
- xg_init_vinsn (&orig_vinsn);
+ xg_clear_vinsn (&cur_vinsn);
- vinsn_from_chars (&orig_vinsn, fr_opcode);
- if (xtensa_format_num_slots (isa, fmt) > 1)
+ vinsn_from_chars (&cur_vinsn, fr_opcode);
+ if (cur_vinsn.num_slots > 1)
wide_insn = TRUE;
- orig_tinsn = orig_vinsn.slots[slot];
+ orig_tinsn = cur_vinsn.slots[slot];
tinsn_immed_from_frag (&orig_tinsn, fragP, slot);
is_loop = xtensa_opcode_is_loop (xtensa_default_isa, orig_tinsn.opcode) == 1;
bytes = xtensa_format_length (isa, fmt);
if (bytes >= 4)
{
- orig_vinsn.slots[slot].opcode =
- xtensa_format_slot_nop_opcode (isa, orig_vinsn.format, slot);
- orig_vinsn.slots[slot].ntok = 0;
+ cur_vinsn.slots[slot].opcode =
+ xtensa_format_slot_nop_opcode (isa, cur_vinsn.format, slot);
+ cur_vinsn.slots[slot].ntok = 0;
}
else
{
bytes += fragP->tc_frag_data.text_expansion[0];
assert (bytes == 2 || bytes == 3);
- build_nop (&orig_vinsn.slots[0], bytes);
+ build_nop (&cur_vinsn.slots[0], bytes);
fragP->fr_fix += fragP->tc_frag_data.text_expansion[0];
}
- vinsn_to_insnbuf (&orig_vinsn, fr_opcode, frag_now, FALSE);
+ vinsn_to_insnbuf (&cur_vinsn, fr_opcode, frag_now, TRUE);
xtensa_insnbuf_to_chars
- (isa, orig_vinsn.insnbuf, (unsigned char *) fr_opcode, 0);
+ (isa, cur_vinsn.insnbuf, (unsigned char *) fr_opcode, 0);
fragP->fr_var = 0;
}
else
first = FALSE;
if (opcode_fits_format_slot (tinsn->opcode, fmt, slot))
{
- tinsn->record_fix = TRUE;
- orig_vinsn.slots[slot] = *tinsn;
+ cur_vinsn.slots[slot] = *tinsn;
}
else
{
- orig_vinsn.slots[slot].opcode =
+ cur_vinsn.slots[slot].opcode =
xtensa_format_slot_nop_opcode (isa, fmt, slot);
- orig_vinsn.slots[slot].ntok = 0;
- orig_vinsn.slots[slot].record_fix = FALSE;
+ cur_vinsn.slots[slot].ntok = 0;
}
- vinsn_to_insnbuf (&orig_vinsn, immed_instr, fragP, TRUE);
- xtensa_insnbuf_to_chars (isa, orig_vinsn.insnbuf,
+ vinsn_to_insnbuf (&cur_vinsn, immed_instr, fragP, TRUE);
+ xtensa_insnbuf_to_chars (isa, cur_vinsn.insnbuf,
(unsigned char *) immed_instr, 0);
fragP->tc_frag_data.is_insn = TRUE;
size = xtensa_format_length (isa, fmt);
if (!opcode_fits_format_slot (tinsn->opcode, fmt, slot))
{
- xtensa_format single_fmt =
- xg_get_single_format (tinsn->opcode);
-
xg_emit_insn_to_buf
- (tinsn, single_fmt, immed_instr + size, fragP,
+ (tinsn, immed_instr + size, fragP,
immed_instr - fragP->fr_literal + size, TRUE);
size += xg_get_single_size (tinsn->opcode);
}
}
else
{
- xtensa_format single_format;
size = xg_get_single_size (tinsn->opcode);
- single_format = xg_get_single_format (tinsn->opcode);
- xg_emit_insn_to_buf (tinsn, single_format, immed_instr,
- fragP,
+ xg_emit_insn_to_buf (tinsn, immed_instr, fragP,
immed_instr - fragP->fr_literal, TRUE);
}
immed_instr += size;
fragP->fr_fix += diff;
}
- /* Clean it up. */
- xg_free_vinsn (&orig_vinsn);
-
/* Check for undefined immediates in LOOP instructions. */
if (is_loop)
{
{
frchain_from = seg_info (segment->seg)->frchainP;
search_frag = frchain_from->frch_root;
- while (search_frag)
+ while (search_frag)
{
search_frag->tc_frag_data.is_literal = TRUE;
search_frag = search_frag->fr_next;
static bfd_boolean recursive = FALSE;
fragS *pool_location = get_literal_pool_location (now_seg);
- bfd_boolean is_init =
+ bfd_boolean is_init =
(now_seg && !strcmp (segment_name (now_seg), INIT_SECTION_NAME));
- bfd_boolean is_fini =
+ bfd_boolean is_fini =
(now_seg && !strcmp (segment_name (now_seg), FINI_SECTION_NAME));
if (pool_location == NULL
/* FIXME: Make tinsn allocation dynamic. */
if (xtensa_opcode_num_operands (isa, opcode) >= MAX_INSN_ARGS)
as_fatal (_("too many operands in instruction"));
- opi->single = XTENSA_UNDEFINED;
- opi->single_size = 0;
- opi->widest = XTENSA_UNDEFINED;
- opi->widest_size = 0;
opi->narrowest = XTENSA_UNDEFINED;
opi->narrowest_size = 0x7F;
+ opi->narrowest_slot = 0;
opi->formats = 0;
opi->num_formats = 0;
opi->issuef = 0;
{
opi->narrowest = fmt;
opi->narrowest_size = fmt_length;
- }
- if (fmt_length > opi->widest_size)
- {
- opi->widest = fmt;
- opi->widest_size = fmt_length;
- }
- if (xtensa_format_num_slots (isa, fmt) == 1)
- {
- if (opi->single_size == 0
- || fmt_length < opi->single_size)
- {
- opi->single = fmt;
- opi->single_size = fmt_length;
- }
+ opi->narrowest_slot = slot;
}
}
}
static int
xg_get_single_size (xtensa_opcode opcode)
{
- assert (op_placement_table[opcode].single != XTENSA_UNDEFINED);
- return op_placement_table[opcode].single_size;
+ return op_placement_table[opcode].narrowest_size;
}
static xtensa_format
xg_get_single_format (xtensa_opcode opcode)
{
- return op_placement_table[opcode].single;
+ return op_placement_table[opcode].narrowest;
+}
+
+
+static int
+xg_get_single_slot (xtensa_opcode opcode)
+{
+ return op_placement_table[opcode].narrowest_slot;
}
\f
default:
/* Symbolic immediates are only allowed on the last immediate
operand. At this time, CONST16 is the only opcode where we
- support non-PC-relative relocations. (It isn't necessary
- to complain about non-PC-relative relocations here, but
- otherwise, no error is reported until the relocations are
- generated, and the assembler won't get that far if there
- are any other errors. It's nice to see all the problems
- at once.) */
+ support non-PC-relative relocations. */
if (i != get_relaxable_immed (insn->opcode)
|| (xtensa_operand_is_PCrelative (isa, insn->opcode, i) != 1
&& insn->opcode != xtensa_const16_opcode))
{
- as_bad (_("invalid symbolic operand %d on '%s'"),
- i, xtensa_opcode_name (isa, insn->opcode));
+ as_bad (_("invalid symbolic operand"));
return TRUE;
}
}
}
-/* Convert the constant operands in the tinsn to insnbuf.
- Return TRUE if there is a symbol in the immediate field.
-
- Before this is called,
- 1) the number of operands are correct
- 2) the tinsn is a ITYPE_INSN
- 3) ONLY the relaxable_ is built
- 4) All operands are O_constant, O_symbol. All constants fit
- The return value tells whether there are any remaining O_symbols. */
-
-static bfd_boolean
-tinsn_to_insnbuf (TInsn *tinsn, xtensa_insnbuf insnbuf)
-{
- static xtensa_insnbuf slotbuf = 0;
- xtensa_isa isa = xtensa_default_isa;
- xtensa_opcode opcode = tinsn->opcode;
- xtensa_format fmt = xg_get_single_format (opcode);
- bfd_boolean has_fixup = FALSE;
- int noperands = xtensa_opcode_num_operands (isa, opcode);
- int i;
- uint32 opnd_value;
- char *file_name;
- unsigned line;
-
- if (!slotbuf)
- slotbuf = xtensa_insnbuf_alloc (isa);
-
- assert (tinsn->insn_type == ITYPE_INSN);
- if (noperands != tinsn->ntok)
- as_fatal (_("operand number mismatch"));
-
- if (xtensa_opcode_encode (isa, fmt, 0, slotbuf, opcode))
- as_fatal (_("cannot encode opcode"));
-
- for (i = 0; i < noperands; ++i)
- {
- expressionS *expr = &tinsn->tok[i];
- switch (expr->X_op)
- {
- case O_register:
- if (xtensa_operand_is_visible (isa, opcode, i) == 0)
- break;
- /* The register number has already been checked in
- expression_maybe_register, so we don't need to check here. */
- opnd_value = expr->X_add_number;
- (void) xtensa_operand_encode (isa, opcode, i, &opnd_value);
- xtensa_operand_set_field (isa, opcode, i, fmt, 0,
- slotbuf, opnd_value);
- break;
-
- case O_constant:
- if (xtensa_operand_is_visible (isa, opcode, i) == 0)
- break;
- as_where (&file_name, &line);
- /* It is a constant and we called this function,
- then we have to try to fit it. */
- xtensa_insnbuf_set_operand (slotbuf, fmt, 0, opcode, i,
- expr->X_add_number, file_name, line);
- break;
-
- default:
- has_fixup = TRUE;
- break;
- }
- }
-
- xtensa_format_encode (isa, fmt, insnbuf);
- xtensa_format_set_slot (isa, fmt, 0, insnbuf, slotbuf);
-
- return has_fixup;
-}
-
-
-/* Convert the constant operands in the tinsn to slotbuf.
- Return TRUE if there is a symbol in the immediate field.
- (Eventually this should replace tinsn_to_insnbuf.) */
-
-/* Before this is called,
- 1) the number of operands are correct
- 2) the tinsn is a ITYPE_INSN
- 3) ONLY the relaxable_ is built
- 4) All operands are
- O_constant, O_symbol
- All constants fit
-
- The return value tells whether there are any remaining O_symbols. */
+/* Encode a TInsn opcode and its constant operands into slotbuf.
+ Return TRUE if there is a symbol in the immediate field. This
+ function assumes that:
+ 1) The number of operands are correct.
+ 2) The insn_type is ITYPE_INSN.
+ 3) The opcode can be encoded in the specified format and slot.
+ 4) Operands are either O_constant or O_symbol, and all constants fit. */
static bfd_boolean
tinsn_to_slotbuf (xtensa_format fmt,
int noperands = xtensa_opcode_num_operands (isa, opcode);
int i;
- *((int *) &slotbuf[0]) = 0;
- *((int *) &slotbuf[1]) = 0;
assert (tinsn->insn_type == ITYPE_INSN);
if (noperands != tinsn->ntok)
as_fatal (_("operand number mismatch"));
}
+/* Encode a single TInsn into an insnbuf. If the opcode can only be encoded
+ into a multi-slot instruction, fill the other slots with NOPs.
+ Return TRUE if there is a symbol in the immediate field. See also the
+ assumptions listed for tinsn_to_slotbuf. */
+
+static bfd_boolean
+tinsn_to_insnbuf (TInsn *tinsn, xtensa_insnbuf insnbuf)
+{
+ static xtensa_insnbuf slotbuf = 0;
+ static vliw_insn vinsn;
+ xtensa_isa isa = xtensa_default_isa;
+ bfd_boolean has_fixup = FALSE;
+ int i;
+
+ if (!slotbuf)
+ {
+ slotbuf = xtensa_insnbuf_alloc (isa);
+ xg_init_vinsn (&vinsn);
+ }
+
+ xg_clear_vinsn (&vinsn);
+
+ bundle_tinsn (tinsn, &vinsn);
+
+ xtensa_format_encode (isa, vinsn.format, insnbuf);
+
+ for (i = 0; i < vinsn.num_slots; i++)
+ {
+ /* Only one slot may have a fix-up because the rest contains NOPs. */
+ has_fixup |=
+ tinsn_to_slotbuf (vinsn.format, i, &vinsn.slots[i], vinsn.slotbuf[i]);
+ xtensa_format_set_slot (isa, vinsn.format, i, insnbuf, vinsn.slotbuf[i]);
+ }
+
+ return has_fixup;
+}
+
+
/* Check the instruction arguments. Return TRUE on failure. */
static bfd_boolean
{
opnum = get_relaxable_immed (opcode);
assert (opnum >= 0);
- if (fragP->tc_frag_data.slot_sub_symbols[slot])
- {
- set_expr_symbol_offset_diff
- (&tinsn->tok[opnum],
- fragP->tc_frag_data.slot_symbols[slot],
- fragP->tc_frag_data.slot_sub_symbols[slot],
- fragP->tc_frag_data.slot_offsets[slot]);
- }
- else
- {
- set_expr_symbol_offset
- (&tinsn->tok[opnum],
- fragP->tc_frag_data.slot_symbols[slot],
- fragP->tc_frag_data.slot_offsets[slot]);
- }
+ set_expr_symbol_offset (&tinsn->tok[opnum],
+ fragP->tc_frag_data.slot_symbols[slot],
+ fragP->tc_frag_data.slot_offsets[slot]);
}
}
for (i = 0; i < MAX_SLOTS; i++)
{
- tinsn_init (&v->slots[i]);
- v->slots[i].opcode = XTENSA_UNDEFINED;
v->slotbuf[i] = xtensa_insnbuf_alloc (isa);
if (v->slotbuf[i] == NULL)
as_fatal (_("out of memory"));
xg_clear_vinsn (vliw_insn *v)
{
int i;
+
+ memset (v, 0, offsetof (vliw_insn, insnbuf));
+
v->format = XTENSA_UNDEFINED;
v->num_slots = 0;
v->inside_bundle = FALSE;
debug_type = xt_saved_debug_type;
for (i = 0; i < MAX_SLOTS; i++)
- {
- memset (&v->slots[i], 0, sizeof (TInsn));
- v->slots[i].opcode = XTENSA_UNDEFINED;
- }
+ v->slots[i].opcode = XTENSA_UNDEFINED;
}
vinsn_has_specific_opcodes (vliw_insn *v)
{
int i;
-
+
for (i = 0; i < v->num_slots; i++)
{
if (v->slots[i].is_specific_opcode)
}
-/* Before this is called, we should have
- filled out the following fields:
-
- 1) the number of operands for each opcode are correct
- 2) the tinsn in the slots are ITYPE_INSN
- 3) ONLY the relaxable_ is built
- 4) All operands are
- O_constant, O_symbol
- All constants fit
-
- The return value tells whether there are any remaining O_symbols. */
+/* Encode a vliw_insn into an insnbuf. Return TRUE if there are any symbolic
+ operands. See also the assumptions listed for tinsn_to_slotbuf. */
static bfd_boolean
vinsn_to_insnbuf (vliw_insn *vinsn,
xtensa_format_set_slot (isa, fmt, slot,
insnbuf, vinsn->slotbuf[slot]);
- /* tinsn_has_fixup tracks if there is a fixup at all.
- record_fixup controls globally. I.E., we use this
- function from several places, some of which are after
- fixups have already been recorded. Finally,
- tinsn->record_fixup controls based on the individual ops,
- which may or may not need it based on the relaxation
- requirements. */
- if (tinsn_has_fixup && record_fixup)
+ if (tinsn_has_fixup)
{
int i;
xtensa_opcode opcode = tinsn->opcode;
case O_hi16:
if (get_relaxable_immed (opcode) == i)
{
- if (tinsn->record_fix || expr->X_op != O_symbol)
+ /* Add a fix record for the instruction, except if this
+ function is being called prior to relaxation, i.e.,
+ if record_fixup is false, and the instruction might
+ be relaxed later. */
+ if (record_fixup
+ || tinsn->is_specific_opcode
+ || !xg_is_relaxable_insn (tinsn, 0))
{
- if (!xg_add_opcode_fix
- (tinsn, i, fmt, slot, expr, fragP,
- frag_offset - fragP->fr_literal))
- as_bad (_("instruction with constant operands does not fit"));
+ xg_add_opcode_fix (tinsn, i, fmt, slot, expr, fragP,
+ frag_offset - fragP->fr_literal);
}
else
{
+ if (expr->X_op != O_symbol)
+ as_bad (_("invalid operand"));
tinsn->symbol = expr->X_add_symbol;
tinsn->offset = expr->X_add_number;
}
}
else
- as_bad (_("invalid operand %d on '%s'"),
- i, xtensa_opcode_name (isa, opcode));
+ as_bad (_("symbolic operand not allowed"));
break;
case O_constant:
case O_register:
break;
- case O_subtract:
- if (get_relaxable_immed (opcode) == i)
- {
- if (tinsn->record_fix)
- as_bad (_("invalid subtract operand"));
- else
- {
- tinsn->symbol = expr->X_add_symbol;
- tinsn->sub_symbol = expr->X_op_symbol;
- tinsn->offset = expr->X_add_number;
- }
- }
- else
- as_bad (_("invalid operand %d on '%s'"),
- i, xtensa_opcode_name (isa, opcode));
- break;
-
default:
- as_bad (_("invalid expression for operand %d on '%s'"),
- i, xtensa_opcode_name (isa, opcode));
+ as_bad (_("expression too complex"));
break;
}
}
}
-/* Set the expression to symbol - minus_sym + offset. */
-
-static void
-set_expr_symbol_offset_diff (expressionS *s,
- symbolS *sym,
- symbolS *minus_sym,
- offsetT offset)
-{
- s->X_op = O_subtract;
- s->X_add_symbol = sym;
- s->X_op_symbol = minus_sym; /* unused */
- s->X_add_number = offset;
-}
-
-
/* Return TRUE if the two expressions are equal. */
bfd_boolean