bfd_boolean density_supported = XCHAL_HAVE_DENSITY;
bfd_boolean absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS;
-/* Maximum width we would pad an unreachable frag to get alignment. */
-#define UNREACHABLE_MAX_WIDTH 8
-
static vliw_insn cur_vinsn;
unsigned xtensa_num_pipe_stages;
{
bfd_reloc_code_real_type reloc;
segT t = expression (tok);
+
if (t == absolute_section
&& xtensa_operand_is_PCrelative (isa, opc, opnd) == 1)
{
gas_assert (insn->insn_type == ITYPE_INSN);
for (i = 0; i < n; ++i)
{
- const expressionS *expr = &insn->tok[i];
+ const expressionS *exp = &insn->tok[i];
+
if (xtensa_operand_is_register (isa, insn->opcode, i) == 1)
continue;
- switch (expr->X_op)
+ switch (exp->X_op)
{
case O_register:
case O_constant:
- if (xg_check_operand (expr->X_add_number, insn->opcode, i))
+ if (xg_check_operand (exp->X_add_number, insn->opcode, i))
return FALSE;
break;
for (i = 0; i < n; ++i)
{
- const expressionS *expr = &insn->tok[i];
+ const expressionS *exp = &insn->tok[i];
+
if (xtensa_operand_is_register (isa, insn->opcode, i) == 1)
continue;
- switch (expr->X_op)
+ switch (exp->X_op)
{
case O_register:
case O_constant:
- if (xg_check_operand (expr->X_add_number, insn->opcode, i))
+ if (xg_check_operand (exp->X_add_number, insn->opcode, i))
return FALSE;
break;
/* If it is a weak symbol or a symbol in a different section,
it cannot be known to fit at assembly time. */
- if (S_IS_WEAK (expr->X_add_symbol)
- || S_GET_SEGMENT (expr->X_add_symbol) != pc_seg)
+ if (S_IS_WEAK (exp->X_add_symbol)
+ || S_GET_SEGMENT (exp->X_add_symbol) != pc_seg)
{
/* For a direct call with --no-longcalls, be optimistic and
assume it will be in range. If the symbol is weak and
symbols even if longcalls is not enabled. */
if (is_direct_call_opcode (insn->opcode)
&& ! pc_frag->tc_frag_data.use_longcalls
- && (! S_IS_WEAK (expr->X_add_symbol)
- || S_IS_DEFINED (expr->X_add_symbol)))
+ && (! S_IS_WEAK (exp->X_add_symbol)
+ || S_IS_DEFINED (exp->X_add_symbol)))
return TRUE;
return FALSE;
}
- symbolP = expr->X_add_symbol;
+ symbolP = exp->X_add_symbol;
sym_frag = symbol_get_frag (symbolP);
- target = S_GET_VALUE (symbolP) + expr->X_add_number;
+ target = S_GET_VALUE (symbolP) + exp->X_add_number;
pc = pc_frag->fr_address + pc_offset;
/* If frag has yet to be reached on this pass, assume it
/* Check to see if it fits. */
for (i = stack_size; i < istack->ninsn; i++)
{
- TInsn *insn = &istack->insn[i];
+ TInsn *tinsn = &istack->insn[i];
- if (insn->insn_type == ITYPE_INSN
- && !tinsn_has_symbolic_operands (insn)
- && !xg_immeds_fit (insn))
+ if (tinsn->insn_type == ITYPE_INSN
+ && !tinsn_has_symbolic_operands (tinsn)
+ && !xg_immeds_fit (tinsn))
{
istack->ninsn = stack_size;
return FALSE;
int opnum,
xtensa_format fmt,
int slot,
- expressionS *expr,
+ expressionS *exp,
fragS *fragP,
offsetT offset)
{
}
else if (opcode == xtensa_const16_opcode)
{
- if (expr->X_op == O_lo16)
+ if (exp->X_op == O_lo16)
{
reloc = encode_reloc (slot);
- expr->X_op = O_symbol;
+ exp->X_op = O_symbol;
}
- else if (expr->X_op == O_hi16)
+ else if (exp->X_op == O_hi16)
{
reloc = encode_alt_reloc (slot);
- expr->X_op = O_symbol;
+ exp->X_op = O_symbol;
}
}
/* Handle erroneous "@h" and "@l" expressions here before they propagate
into the symbol table where the generic portions of the assembler
won't know what to do with them. */
- if (expr->X_op == O_lo16 || expr->X_op == O_hi16)
+ if (exp->X_op == O_lo16 || exp->X_op == O_hi16)
{
as_bad (_("invalid expression for operand %i of '%s'"),
opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
}
fmt_length = xtensa_format_length (xtensa_default_isa, fmt);
- the_fix = fix_new_exp (fragP, offset, fmt_length, expr,
+ the_fix = fix_new_exp (fragP, offset, fmt_length, exp,
howto->pc_relative, reloc);
the_fix->fx_no_overflow = 1;
- 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.X_add_symbol = exp->X_add_symbol;
+ the_fix->tc_fix_data.X_add_number = exp->X_add_number;
the_fix->tc_fix_data.slot = slot;
return TRUE;
be accompanied by major changes to make use of that data.
In any event, we can tell that we are expanding from a single-slot
- three-byte format to a wider one with the logic below. */
+ format to a wider one with the logic below. */
- if (fmt_size <= 3 && fragP->tc_frag_data.text_expansion[0] != 3)
- return 3 + fragP->tc_frag_data.text_expansion[0];
- else
- return 3;
+ int i;
+ int relaxed_size = fmt_size + fragP->tc_frag_data.text_expansion[0];
+
+ for (i = 0; i < xtensa_isa_num_formats (isa); i++)
+ {
+ if (relaxed_size == xtensa_format_length (isa, i))
+ return relaxed_size;
+ }
+
+ return 3;
}
if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
bfd_boolean
xtensa_fix_adjustable (fixS *fixP)
{
- /* An offset is not allowed in combination with the difference of two
- symbols, but that cannot be easily detected after a local symbol
- has been adjusted to a (section+offset) form. Return 0 so that such
- an fix will not be adjusted. */
- if (fixP->fx_subsy && fixP->fx_addsy && fixP->fx_offset
- && relaxable_section (S_GET_SEGMENT (fixP->fx_subsy)))
- return 0;
-
/* We need the symbol name for the VTABLE entries. */
if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
break;
}
- /* An offset is only allowed when it results from adjusting a
- local symbol into a section-relative offset. If the offset
- came from the original expression, tc_fix_adjustable will have
- prevented the fix from being converted to a section-relative
- form so that we can flag the error here. */
- if (fixP->fx_offset != 0 && !symbol_section_p (fixP->fx_addsy))
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("cannot represent subtraction with an offset"));
-
val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
- S_GET_VALUE (fixP->fx_subsy));
{
gas_assert (finish_frag);
frag_var (rs_machine_dependent,
- UNREACHABLE_MAX_WIDTH, UNREACHABLE_MAX_WIDTH,
+ xtensa_fetch_width, xtensa_fetch_width,
RELAX_UNREACHABLE,
frag_now->fr_symbol, frag_now->fr_offset, NULL);
xtensa_set_frag_assembly_state (frag_now);
{
gas_assert (finish_frag);
frag_var (rs_machine_dependent,
- UNREACHABLE_MAX_WIDTH, UNREACHABLE_MAX_WIDTH,
+ xtensa_fetch_width, xtensa_fetch_width,
RELAX_MAYBE_UNREACHABLE,
frag_now->fr_symbol, frag_now->fr_offset, NULL);
xtensa_set_frag_assembly_state (frag_now);
static bfd_boolean
is_narrow_branch_guaranteed_in_range (fragS *fragP, TInsn *tinsn)
{
- const expressionS *expr = &tinsn->tok[1];
- symbolS *symbolP = expr->X_add_symbol;
- offsetT max_distance = expr->X_add_number;
+ const expressionS *exp = &tinsn->tok[1];
+ symbolS *symbolP = exp->X_add_symbol;
+ offsetT max_distance = exp->X_add_number;
fragS *target_frag;
- if (expr->X_op != O_symbol)
+ if (exp->X_op != O_symbol)
return FALSE;
target_frag = symbol_get_frag (symbolP);
for (expr_sym = expr_symbols; expr_sym;
expr_sym = symbol_get_tc (expr_sym)->next_expr_symbol)
{
- expressionS *expr = symbol_get_value_expression (expr_sym);
+ expressionS *exp = symbol_get_value_expression (expr_sym);
- if (expr->X_op == O_subtract)
+ if (exp->X_op == O_subtract)
{
- symbolS *left = expr->X_add_symbol;
- symbolS *right = expr->X_op_symbol;
+ symbolS *left = exp->X_add_symbol;
+ symbolS *right = exp->X_op_symbol;
/* Difference of two symbols not in the same section
are handled with relocations in the linker. */
static bfd_boolean
is_empty_loop (const TInsn *insn, fragS *fragP)
{
- const expressionS *expr;
+ const expressionS *exp;
symbolS *symbolP;
fragS *next_fragP;
if (insn->ntok <= LOOP_IMMED_OPN)
return FALSE;
- expr = &insn->tok[LOOP_IMMED_OPN];
+ exp = &insn->tok[LOOP_IMMED_OPN];
- if (expr->X_op != O_symbol)
+ if (exp->X_op != O_symbol)
return FALSE;
- symbolP = expr->X_add_symbol;
+ symbolP = exp->X_add_symbol;
if (!symbolP)
return FALSE;
static bfd_boolean
is_local_forward_loop (const TInsn *insn, fragS *fragP)
{
- const expressionS *expr;
+ const expressionS *exp;
symbolS *symbolP;
fragS *next_fragP;
if (insn->ntok <= LOOP_IMMED_OPN)
return FALSE;
- expr = &insn->tok[LOOP_IMMED_OPN];
+ exp = &insn->tok[LOOP_IMMED_OPN];
- if (expr->X_op != O_symbol)
+ if (exp->X_op != O_symbol)
return FALSE;
- symbolP = expr->X_add_symbol;
+ symbolP = exp->X_add_symbol;
if (!symbolP)
return FALSE;
{
if (target_size <= 4)
return 2;
- gas_assert (target_size == 8);
- return 3;
+
+ if (target_size <= 8)
+ return 3;
+
+ if (target_size <= 16)
+ return 4;
+
+ if (target_size <= 32)
+ return 5;
+
+ if (target_size <= 64)
+ return 6;
+
+ if (target_size <= 128)
+ return 7;
+
+ if (target_size <= 256)
+ return 8;
+
+ if (target_size <= 512)
+ return 9;
+
+ if (target_size <= 1024)
+ return 10;
+
+ gas_assert (0);
+ return 0;
}
static int
branch_align_power (segT sec)
{
- /* If the Xtensa processor has a fetch width of 8 bytes, and the section
- is aligned to at least an 8-byte boundary, then a branch target need
- only fit within an 8-byte aligned block of memory to avoid a stall.
- Otherwise, try to fit branch targets within 4-byte aligned blocks
- (which may be insufficient, e.g., if the section has no alignment, but
- it's good enough). */
- if (xtensa_fetch_width == 8)
- {
- if (get_recorded_alignment (sec) >= 3)
- return 3;
- }
- else
- gas_assert (xtensa_fetch_width == 4);
+ /* If the Xtensa processor has a fetch width of X, and
+ the section is aligned to at least that boundary, then a branch
+ target need only fit within that aligned block of memory to avoid
+ a stall. Otherwise, try to fit branch targets within 4-byte
+ aligned blocks (which may be insufficient, e.g., if the section
+ has no alignment, but it's good enough). */
+ int fetch_align = get_text_align_power(xtensa_fetch_width);
+ int sec_align = get_recorded_alignment (sec);
+
+ if (sec_align >= fetch_align)
+ return fetch_align;
return 2;
}
{
if (this_frag->fr_subtype == RELAX_UNREACHABLE)
{
- gas_assert (opt_diff <= UNREACHABLE_MAX_WIDTH);
+ gas_assert (opt_diff <= (signed) xtensa_fetch_width);
return opt_diff;
}
return 0;
/* The idea: widen everything you can to get a target or loop aligned,
then start using NOPs.
- When we must have a NOP, here is a table of how we decide
- (so you don't have to fight through the control flow below):
-
wide_nops = the number of wide NOPs available for aligning
narrow_nops = the number of narrow NOPs available for aligning
(a subset of wide_nops)
widens = the number of narrow instructions that should be widened
- Desired wide narrow
- Diff nop nop widens
- 1 0 0 1
- 2 0 1 0
- 3a 1 0 0
- b 0 1 1 (case 3a makes this case unnecessary)
- 4a 1 0 1
- b 0 2 0
- c 0 1 2 (case 4a makes this case unnecessary)
- 5a 1 0 2
- b 1 1 0
- c 0 2 1 (case 5b makes this case unnecessary)
- 6a 2 0 0
- b 1 0 3
- c 0 1 4 (case 6b makes this case unnecessary)
- d 1 1 1 (case 6a makes this case unnecessary)
- e 0 2 2 (case 6a makes this case unnecessary)
- f 0 3 0 (case 6a makes this case unnecessary)
- 7a 1 0 4
- b 2 0 1
- c 1 1 2 (case 7b makes this case unnecessary)
- d 0 1 5 (case 7a makes this case unnecessary)
- e 0 2 3 (case 7b makes this case unnecessary)
- f 0 3 1 (case 7b makes this case unnecessary)
- g 1 2 1 (case 7b makes this case unnecessary)
*/
static long
int num_widens,
int desired_diff)
{
+ int nops_needed;
+ int nop_bytes;
+ int extra_bytes;
int bytes_short = desired_diff - num_widens;
- gas_assert (desired_diff >= 0 && desired_diff < 8);
+ gas_assert (desired_diff >= 0
+ && desired_diff < (signed) xtensa_fetch_width);
if (desired_diff == 0)
return 0;
/* 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->fr_subtype == RELAX_FILL_NOP)
+ nops_needed = desired_diff / 3;
+
+ /* If there aren't enough nops, don't widen. */
+ if (nops_needed > wide_nops)
+ return 0;
+
+ /* First try it with all wide nops. */
+ nop_bytes = nops_needed * 3;
+ extra_bytes = desired_diff - nop_bytes;
+
+ if (nop_bytes + num_widens >= desired_diff)
{
- switch (desired_diff)
- {
- case 1:
- return 0;
- case 2:
- if (!this_frag->tc_frag_data.is_no_density && narrow_nops == 1)
- return 2; /* case 2 */
- return 0;
- case 3:
- if (wide_nops > 1)
- return 0;
- else
- return 3; /* case 3a */
- case 4:
- if (num_widens >= 1 && wide_nops == 1)
- return 3; /* case 4a */
- if (!this_frag->tc_frag_data.is_no_density && narrow_nops == 2)
- return 2; /* case 4b */
- return 0;
- case 5:
- if (num_widens >= 2 && wide_nops == 1)
- return 3; /* case 5a */
- /* We will need two nops. Are there enough nops
- between here and the align target? */
- if (wide_nops < 2 || narrow_nops == 0)
- return 0;
- /* Are there other nops closer that can serve instead? */
- if (wide_nops > 2 && narrow_nops > 1)
- return 0;
- /* Take the density one first, because there might not be
- another density one available. */
- if (!this_frag->tc_frag_data.is_no_density)
- return 2; /* case 5b narrow */
- else
- return 3; /* case 5b wide */
- return 0;
- case 6:
- if (wide_nops == 2)
- return 3; /* case 6a */
- else if (num_widens >= 3 && wide_nops == 1)
- return 3; /* case 6b */
- return 0;
- case 7:
- if (wide_nops == 1 && num_widens >= 4)
- return 3; /* case 7a */
- else if (wide_nops == 2 && num_widens >= 1)
- return 3; /* case 7b */
- return 0;
- default:
- gas_assert (0);
- }
+ if (this_frag->fr_subtype == RELAX_FILL_NOP)
+ return 3;
+ else if (num_widens == extra_bytes)
+ return 1;
+ return 0;
}
- else
+
+ /* Add a narrow nop. */
+ nops_needed++;
+ nop_bytes += 2;
+ extra_bytes -= 2;
+ if (narrow_nops == 0 || nops_needed > wide_nops)
+ return 0;
+
+ if (nop_bytes + num_widens >= desired_diff && extra_bytes >= 0)
{
- /* We will need a NOP no matter what, but should we widen
- this instruction to help?
+ if (this_frag->fr_subtype == RELAX_FILL_NOP)
+ return !this_frag->tc_frag_data.is_no_density ? 2 : 3;
+ else if (num_widens == extra_bytes)
+ return 1;
+ return 0;
+ }
- This is a RELAX_NARROW frag. */
- switch (desired_diff)
- {
- case 1:
- gas_assert (0);
- return 0;
- case 2:
- case 3:
- return 0;
- case 4:
- if (wide_nops >= 1 && num_widens == 1)
- return 1; /* case 4a */
- return 0;
- case 5:
- if (wide_nops >= 1 && num_widens == 2)
- return 1; /* case 5a */
- return 0;
- case 6:
- if (wide_nops >= 2)
- return 0; /* case 6a */
- else if (wide_nops >= 1 && num_widens == 3)
- return 1; /* case 6b */
- return 0;
- case 7:
- if (wide_nops >= 1 && num_widens == 4)
- return 1; /* case 7a */
- else if (wide_nops >= 2 && num_widens == 1)
- return 1; /* case 7b */
- return 0;
- default:
- gas_assert (0);
- return 0;
- }
+ /* Replace a wide nop with a narrow nop--we can get here if
+ extra_bytes was negative in the previous conditional. */
+ if (narrow_nops == 1)
+ return 0;
+ nop_bytes--;
+ extra_bytes++;
+ if (nop_bytes + num_widens >= desired_diff)
+ {
+ if (this_frag->fr_subtype == RELAX_FILL_NOP)
+ return !this_frag->tc_frag_data.is_no_density ? 2 : 3;
+ else if (num_widens == extra_bytes)
+ return 1;
+ return 0;
}
- gas_assert (0);
+
+ /* If we can't satisfy any of the above cases, then we can't align
+ using padding or fill nops. */
return 0;
}
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;
- if (dest_seg)
- S_SET_SEGMENT (lit_sym, dest_seg);
+ segT dseg = symbol_get_frag (lit_sym)->tc_frag_data.lit_seg;
+ if (dseg)
+ S_SET_SEGMENT (lit_sym, dseg);
}
}
for (i = 0; i < noperands; i++)
{
- expressionS *expr = &tinsn->tok[i];
+ expressionS *exp = &tinsn->tok[i];
int rc;
unsigned line;
char *file_name;
uint32 opnd_value;
- switch (expr->X_op)
+ switch (exp->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;
+ opnd_value = exp->X_add_number;
(void) xtensa_operand_encode (isa, opcode, i, &opnd_value);
rc = xtensa_operand_set_field (isa, opcode, i, fmt, slot, slotbuf,
opnd_value);
/* It is a constant and we called this function
then we have to try to fit it. */
xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode, i,
- expr->X_add_number, file_name, line);
+ exp->X_add_number, file_name, line);
break;
default:
for (i = 0; i < noperands; i++)
{
- expressionS* expr = &tinsn->tok[i];
- switch (expr->X_op)
+ expressionS* exp = &tinsn->tok[i];
+ switch (exp->X_op)
{
case O_symbol:
case O_lo16:
|| tinsn->is_specific_opcode
|| !xg_is_relaxable_insn (tinsn, 0))
{
- xg_add_opcode_fix (tinsn, i, fmt, slot, expr, fragP,
+ xg_add_opcode_fix (tinsn, i, fmt, slot, exp, fragP,
frag_offset - fragP->fr_literal);
}
else
{
- if (expr->X_op != O_symbol)
+ if (exp->X_op != O_symbol)
as_bad (_("invalid operand"));
- tinsn->symbol = expr->X_add_symbol;
- tinsn->offset = expr->X_add_number;
+ tinsn->symbol = exp->X_add_symbol;
+ tinsn->offset = exp->X_add_number;
}
}
else