GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
#include "tc-xtensa.h"
#include "subsegs.h"
#include "xtensa-relax.h"
-#include "xtensa-istack.h"
#include "dwarf2dbg.h"
+#include "xtensa-istack.h"
#include "struc-symbol.h"
#include "xtensa-config.h"
static xtensa_opcode xtensa_callx12_opcode;
static xtensa_opcode xtensa_const16_opcode;
static xtensa_opcode xtensa_entry_opcode;
+static xtensa_opcode xtensa_extui_opcode;
static xtensa_opcode xtensa_movi_opcode;
static xtensa_opcode xtensa_movi_n_opcode;
static xtensa_opcode xtensa_isync_opcode;
symbolS *sym;
tinsn_init (targ);
- targ->linenum = insn->linenum;
+ targ->debug_line = insn->debug_line;
+ targ->loc_directive_seen = insn->loc_directive_seen;
switch (bi->typ)
{
case INSTR_INSTR:
case INSTR_INSTR:
new_insn->insn_type = ITYPE_INSN;
new_insn->opcode = instr_spec->opcode;
- new_insn->is_specific_opcode = FALSE;
- 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->linenum = old_insn->linenum;
break;
case INSTR_LABEL_DEF:
- as_bad (_("INSTR_LABEL_DEF not supported yet"));
- break;
+ abort ();
}
+ new_insn->is_specific_opcode = FALSE;
+ new_insn->debug_line = old_insn->debug_line;
+ new_insn->loc_directive_seen = old_insn->loc_directive_seen;
for (b_op = instr_spec->ops; b_op != NULL; b_op = b_op->next)
{
if (tinsn_has_invalid_symbolic_operands (orig_insn))
return TRUE;
+ /* Special case for extui opcode which has constraints not handled
+ by the ordinary operand encoding checks. The number of operands
+ and related syntax issues have already been checked. */
+ if (orig_insn->opcode == xtensa_extui_opcode)
+ {
+ int shiftimm = orig_insn->tok[2].X_add_number;
+ int maskimm = orig_insn->tok[3].X_add_number;
+ if (shiftimm + maskimm > 32)
+ {
+ as_bad (_("immediate operands sum to greater than 32"));
+ return TRUE;
+ }
+ }
+
/* If the instruction will definitely need to be relaxed, it is better
to expand it now for better scheduling. Decide whether to expand
now.... */
static bfd_boolean
relaxable_section (asection *sec)
{
- return (sec->flags & SEC_DEBUGGING) == 0;
+ return ((sec->flags & SEC_DEBUGGING) == 0
+ && strcmp (sec->name, ".eh_frame") != 0);
}
xtensa_callx12_opcode = xtensa_opcode_lookup (isa, "callx12");
xtensa_const16_opcode = xtensa_opcode_lookup (isa, "const16");
xtensa_entry_opcode = xtensa_opcode_lookup (isa, "entry");
+ xtensa_extui_opcode = xtensa_opcode_lookup (isa, "extui");
xtensa_movi_opcode = xtensa_opcode_lookup (isa, "movi");
xtensa_movi_n_opcode = xtensa_opcode_lookup (isa, "movi.n");
xtensa_isync_opcode = xtensa_opcode_lookup (isa, "isync");
md_assemble (char *str)
{
xtensa_isa isa = xtensa_default_isa;
- char *opname, *file_name;
+ char *opname;
unsigned opnamelen;
bfd_boolean has_underbar = FALSE;
char *arg_strings[MAX_INSN_ARGS];
return;
}
- /* 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);
+ /* Record the line number for each TInsn, because a FLIX bundle may be
+ spread across multiple input lines and individual instructions may be
+ moved around in some cases. */
+ orig_insn.loc_directive_seen = dwarf2_loc_directive_seen;
+ dwarf2_where (&orig_insn.debug_line);
+ dwarf2_consume_line_info ();
xg_add_branch_and_loop_targets (&orig_insn);
}
+/* tc_symbol_new_hook */
+
+symbolS *expr_symbols = NULL;
+
+void
+xtensa_symbol_new_hook (symbolS *sym)
+{
+ if (S_GET_SEGMENT (sym) == expr_section)
+ {
+ symbol_get_tc (sym)->next_expr_symbol = expr_symbols;
+ expr_symbols = sym;
+ }
+}
+
+
+
void
md_apply_fix (fixS *fixP, valueT *valP, segT seg)
{
char *
md_atof (int type, char *litP, int *sizeP)
{
- int prec;
- LITTLENUM_TYPE words[4];
- char *t;
- int i;
-
- switch (type)
- {
- case 'f':
- prec = 2;
- break;
-
- case 'd':
- prec = 4;
- break;
-
- default:
- *sizeP = 0;
- return "bad call to md_atof";
- }
-
- t = atof_ieee (input_line_pointer, type, words);
- if (t)
- input_line_pointer = t;
-
- *sizeP = prec * 2;
-
- for (i = prec - 1; i >= 0; i--)
- {
- int idx = i;
- if (target_big_endian)
- idx = (prec - 1 - i);
-
- md_number_to_chars (litP, (valueT) words[idx], 2);
- litP += 2;
- }
-
- return NULL;
+ return ieee_md_atof (type, litP, sizeP, target_big_endian);
}
bfd_boolean is_jump = FALSE;
bfd_boolean is_branch = FALSE;
xtensa_isa isa = xtensa_default_isa;
- int i;
int insn_size;
int extra_space;
char *f = NULL;
int slot;
- unsigned current_line, best_linenum;
- char *current_file;
+ struct dwarf2_line_info debug_line;
+ bfd_boolean loc_directive_seen = FALSE;
+ TInsn *tinsn;
- best_linenum = UINT_MAX;
+ memset (&debug_line, 0, sizeof (struct dwarf2_line_info));
if (generating_literals)
{
xtensa_set_frag_assembly_state (frag_now);
}
- for (i = 0; i < vinsn->num_slots; i++)
+ for (slot = 0; slot < vinsn->num_slots; slot++)
{
+ tinsn = &vinsn->slots[slot];
+
/* See if the instruction implies an aligned section. */
- if (xtensa_opcode_is_loop (isa, vinsn->slots[i].opcode) == 1)
+ if (xtensa_opcode_is_loop (isa, tinsn->opcode) == 1)
record_alignment (now_seg, 2);
- /* Also determine the best line number for debug info. */
- best_linenum = vinsn->slots[i].linenum < best_linenum
- ? vinsn->slots[i].linenum : best_linenum;
+ /* Determine the best line number for debug info. */
+ if ((tinsn->loc_directive_seen || !loc_directive_seen)
+ && (tinsn->debug_line.filenum != debug_line.filenum
+ || tinsn->debug_line.line < debug_line.line
+ || tinsn->debug_line.column < debug_line.column))
+ debug_line = tinsn->debug_line;
+ if (tinsn->loc_directive_seen)
+ loc_directive_seen = TRUE;
}
/* Special cases for instructions that force an alignment... */
xtensa_insnbuf_to_chars (isa, vinsn->insnbuf, (unsigned char *) f, 0);
- /* 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);
+ if (debug_type == DEBUG_DWARF2 || loc_directive_seen)
+ dwarf2_gen_line_info (frag_now_fix () - (insn_size + extra_space),
+ &debug_line);
for (slot = 0; slot < vinsn->num_slots; slot++)
{
- TInsn *tinsn = &vinsn->slots[slot];
+ 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_offsets[slot] = tinsn->offset;
static void xtensa_fix_target_frags (void);
static void xtensa_mark_narrow_branches (void);
static void xtensa_mark_zcl_first_insns (void);
+static void xtensa_mark_difference_of_two_symbols (void);
static void xtensa_fix_a0_b_retw_frags (void);
static void xtensa_fix_b_j_loop_end_frags (void);
static void xtensa_fix_close_loop_end_frags (void);
}
+/* Some difference-of-symbols expressions make it out to the linker. Some
+ don't. If one does, then the linker can optimize between the two labels.
+ If it doesn't, then the linker shouldn't. */
+
+static void
+xtensa_mark_difference_of_two_symbols (void)
+{
+ symbolS *expr_sym;
+
+ 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);
+
+ if (expr->X_op == O_subtract)
+ {
+ symbolS *left = expr->X_add_symbol;
+ symbolS *right = expr->X_op_symbol;
+
+ /* Difference of two symbols not in the same section
+ are handled with relocations in the linker. */
+ if (S_GET_SEGMENT (left) == S_GET_SEGMENT (right))
+ {
+ fragS *start;
+ fragS *end;
+
+ if (symbol_get_frag (left)->fr_address
+ <= symbol_get_frag (right)->fr_address)
+ {
+ start = symbol_get_frag (left);
+ end = symbol_get_frag (right);
+ }
+ else
+ {
+ start = symbol_get_frag (right);
+ end = symbol_get_frag (left);
+ }
+ do
+ {
+ start->tc_frag_data.is_no_transform = 1;
+ start = start->fr_next;
+ }
+ while (start && start->fr_address < end->fr_address);
+ }
+ }
+ }
+}
+
+
/* Re-process all of the fragments looking to convert all of the
RELAX_ADD_NOP_IF_A0_B_RETW. If the next instruction is a
conditional branch or a retw/retw.n, convert this frag to one that
xtensa_find_unmarked_state_frags ();
xtensa_mark_frags_for_org ();
+ xtensa_mark_difference_of_two_symbols ();
xtensa_create_property_segments (get_frag_is_literal,
NULL,