/* tc-xtensa.c -- Assemble Xtensa instructions.
- Copyright (C) 2003-2016 Free Software Foundation, Inc.
+ Copyright (C) 2003-2023 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#include "xtensa-relax.h"
#include "dwarf2dbg.h"
#include "xtensa-istack.h"
-#include "struc-symbol.h"
-#include "xtensa-config.h"
-
-/* Provide default values for new configuration settings. */
-#ifndef XSHAL_ABI
-#define XSHAL_ABI 0
-#endif
+#include "xtensa-dynconfig.h"
+#include "elf/xtensa.h"
#ifndef uint32
#define uint32 unsigned int
/* Flags to indicate whether the hardware supports the density and
absolute literals options. */
-bfd_boolean density_supported = XCHAL_HAVE_DENSITY;
-bfd_boolean absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS;
+bool density_supported;
+bool absolute_literals_supported;
+
+static unsigned microarch_earliest;
static vliw_insn cur_vinsn;
unsigned xtensa_num_pipe_stages;
-unsigned xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH;
+unsigned xtensa_fetch_width;
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
back end. */
-static bfd_boolean past_xtensa_end = FALSE;
+static bool past_xtensa_md_finish = false;
/* Flags for properties of the last instruction in a segment. */
#define FLAG_IS_A0_WRITER 0x1
/* Required branch target alignment. */
#define XTENSA_PROP_BT_ALIGN_REQUIRE 0x3
-#define GET_XTENSA_PROP_BT_ALIGN(flag) \
- (((unsigned) ((flag) & (XTENSA_PROP_BT_ALIGN_MASK))) >> 9)
#define SET_XTENSA_PROP_BT_ALIGN(flag, align) \
(((flag) & (~XTENSA_PROP_BT_ALIGN_MASK)) | \
(((align) << 9) & XTENSA_PROP_BT_ALIGN_MASK))
#define XTENSA_PROP_ALIGNMENT_MASK 0x0001f000
-#define GET_XTENSA_PROP_ALIGNMENT(flag) \
- (((unsigned) ((flag) & (XTENSA_PROP_ALIGNMENT_MASK))) >> 12)
#define SET_XTENSA_PROP_ALIGNMENT(flag, align) \
(((flag) & (~XTENSA_PROP_ALIGNMENT_MASK)) | \
(((align) << 12) & XTENSA_PROP_ALIGNMENT_MASK))
const char *suffix;
int length;
bfd_reloc_code_real_type reloc;
- unsigned char operator;
+ operatorT operator;
};
#define SUFFIX_MAP(str, reloc, op) { str, sizeof (str) - 1, reloc, op }
SUFFIX_MAP ("tlscall", BFD_RELOC_XTENSA_TLS_CALL, O_tlscall),
SUFFIX_MAP ("tpoff", BFD_RELOC_XTENSA_TLS_TPOFF, O_tpoff),
SUFFIX_MAP ("dtpoff", BFD_RELOC_XTENSA_TLS_DTPOFF, O_dtpoff),
- { (char *) 0, 0, BFD_RELOC_UNUSED, 0 }
};
typedef struct
{
const char *name;
- bfd_boolean can_be_negated;
+ bool can_be_negated;
} directive_infoS;
const directive_infoS directive_info[] =
{
- { "none", FALSE },
- { "literal", FALSE },
- { "density", TRUE },
- { "transform", TRUE },
- { "freeregs", FALSE },
- { "longcalls", TRUE },
- { "literal_prefix", FALSE },
- { "schedule", TRUE },
- { "absolute-literals", TRUE }
+ { "none", false },
+ { "literal", false },
+ { "density", true },
+ { "transform", true },
+ { "freeregs", false },
+ { "longcalls", true },
+ { "literal_prefix", false },
+ { "schedule", true },
+ { "absolute-literals", true }
};
-bfd_boolean directive_state[] =
-{
- FALSE, /* none */
- FALSE, /* literal */
-#if !XCHAL_HAVE_DENSITY
- FALSE, /* density */
-#else
- TRUE, /* density */
-#endif
- TRUE, /* transform */
- FALSE, /* freeregs */
- FALSE, /* longcalls */
- FALSE, /* literal_prefix */
- FALSE, /* schedule */
-#if XSHAL_USE_ABSOLUTE_LITERALS
- TRUE /* absolute_literals */
-#else
- FALSE /* absolute_literals */
-#endif
+bool directive_state[] =
+{
+ false, /* none */
+ false, /* literal */
+ false, /* density */
+ true, /* transform */
+ false, /* freeregs */
+ false, /* longcalls */
+ false, /* literal_prefix */
+ false, /* schedule */
+ false /* absolute_literals */
};
/* A circular list of all potential and actual literal pool locations
addressT addr;
short priority; /* 1, 2, or 3 -- 1 is highest */
short original_priority;
+ int literal_count;
};
/* Map a segment to its litpool_frag list. */
static struct litpool_seg litpool_seg_list;
+/* Limit maximal size of auto litpool by half of the j range. */
+#define MAX_AUTO_POOL_LITERALS 16384
+
+/* Limit maximal size of explicit literal pool by l32r range. */
+#define MAX_EXPLICIT_POOL_LITERALS 65536
+
+#define MAX_POOL_LITERALS \
+ (auto_litpools ? MAX_AUTO_POOL_LITERALS : MAX_EXPLICIT_POOL_LITERALS)
/* Directive functions. */
/* Various Other Internal Functions. */
-extern bfd_boolean xg_is_single_relaxable_insn (TInsn *, TInsn *, bfd_boolean);
-static bfd_boolean xg_build_to_insn (TInsn *, TInsn *, BuildInstr *);
+extern bool xg_is_single_relaxable_insn (TInsn *, TInsn *, bool);
+static bool xg_build_to_insn (TInsn *, TInsn *, BuildInstr *);
static void xtensa_mark_literal_pool_location (void);
static addressT get_expanded_loop_offset (xtensa_opcode);
static fragS *get_literal_pool_location (segT);
static void set_literal_pool_location (segT, fragS *);
static void xtensa_set_frag_assembly_state (fragS *);
static void finish_vinsn (vliw_insn *);
-static bfd_boolean emit_single_op (TInsn *);
+static bool emit_single_op (TInsn *);
static int total_frag_text_expansion (fragS *);
-static bfd_boolean use_trampolines = TRUE;
+static bool use_trampolines = true;
static void xtensa_check_frag_count (void);
-static void xtensa_create_trampoline_frag (bfd_boolean);
+static void xtensa_create_trampoline_frag (bool);
static void xtensa_maybe_create_trampoline_frag (void);
struct trampoline_frag;
-static int init_trampoline_frag (struct trampoline_frag *);
-static void xtensa_maybe_create_literal_pool_frag (bfd_boolean, bfd_boolean);
-static bfd_boolean auto_litpools = FALSE;
-static int auto_litpool_limit = 10000;
+static int init_trampoline_frag (fragS *);
+static fixS *xg_append_jump (fragS *fragP, symbolS *sym, offsetT offset);
+static void xtensa_maybe_create_literal_pool_frag (bool, bool);
+static bool auto_litpools = false;
+static int auto_litpool_limit = 0;
+static bool xtensa_is_init_fini (segT seg);
/* Alignment Functions. */
static int get_text_align_power (unsigned);
-static int get_text_align_max_fill_size (int, bfd_boolean, bfd_boolean);
+static int get_text_align_max_fill_size (int, bool, bool);
static int branch_align_power (segT);
/* Helpers for xtensa_relax_frag(). */
/* Accessors for additional per-subsegment information. */
static unsigned get_last_insn_flags (segT, subsegT);
-static void set_last_insn_flags (segT, subsegT, unsigned, bfd_boolean);
+static void set_last_insn_flags (segT, subsegT, unsigned, bool);
static float get_subseg_total_freq (segT, subsegT);
static float get_subseg_target_freq (segT, subsegT);
static void set_subseg_freq (segT, subsegT, float, float);
static void xtensa_switch_to_non_abs_literal_fragment (emit_state *);
static void xtensa_switch_section_emit_state (emit_state *, segT, subsegT);
static void xtensa_restore_emit_state (emit_state *);
-static segT cache_literal_section (bfd_boolean);
-
-/* Import from elf32-xtensa.c in BFD library. */
-
-extern asection *xtensa_make_property_section (asection *, const char *);
+static segT cache_literal_section (bool);
/* op_placement_info functions. */
static void init_op_placement_info_table (void);
-extern bfd_boolean opcode_fits_format_slot (xtensa_opcode, xtensa_format, int);
+extern bool 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. */
-static bfd_boolean tinsn_has_symbolic_operands (const TInsn *);
-static bfd_boolean tinsn_has_invalid_symbolic_operands (const TInsn *);
-static bfd_boolean tinsn_has_complex_operands (const TInsn *);
-static bfd_boolean tinsn_to_insnbuf (TInsn *, xtensa_insnbuf);
-static bfd_boolean tinsn_check_arguments (const TInsn *);
+static bool tinsn_has_symbolic_operands (const TInsn *);
+static bool tinsn_has_invalid_symbolic_operands (const TInsn *);
+static bool tinsn_has_complex_operands (const TInsn *);
+static bool tinsn_to_insnbuf (TInsn *, xtensa_insnbuf);
+static bool tinsn_check_arguments (const TInsn *);
static void tinsn_from_chars (TInsn *, char *, int);
static void tinsn_immed_from_frag (TInsn *, fragS *, int);
static int get_num_stack_text_bytes (IStack *);
static int get_num_stack_literal_bytes (IStack *);
-static bfd_boolean tinsn_to_slotbuf (xtensa_format, int, TInsn *, xtensa_insnbuf);
+static bool tinsn_to_slotbuf (xtensa_format, int, TInsn *, xtensa_insnbuf);
/* vliw_insn functions. */
static void xg_init_vinsn (vliw_insn *);
static void xg_copy_vinsn (vliw_insn *, vliw_insn *);
static void xg_clear_vinsn (vliw_insn *);
-static bfd_boolean vinsn_has_specific_opcodes (vliw_insn *);
+static bool vinsn_has_specific_opcodes (vliw_insn *);
static void xg_free_vinsn (vliw_insn *);
-static bfd_boolean vinsn_to_insnbuf
- (vliw_insn *, char *, fragS *, bfd_boolean);
+static bool vinsn_to_insnbuf
+ (vliw_insn *, char *, fragS *, bool);
static void vinsn_from_chars (vliw_insn *, char *);
/* Expression Utilities. */
-bfd_boolean expr_is_const (const expressionS *);
+bool expr_is_const (const expressionS *);
offsetT get_expr_const (const expressionS *);
void set_expr_const (expressionS *, offsetT);
-bfd_boolean expr_is_register (const expressionS *);
+bool expr_is_register (const expressionS *);
offsetT get_expr_register (const expressionS *);
void set_expr_symbol_offset (expressionS *, symbolS *, offsetT);
-bfd_boolean expr_is_equal (expressionS *, expressionS *);
+bool expr_is_equal (expressionS *, expressionS *);
static void copy_expr (expressionS *, const expressionS *);
/* Section renaming. */
\f
/* Command-line Options. */
-bfd_boolean use_literal_section = TRUE;
+bool use_literal_section = true;
enum flix_level produce_flix = FLIX_ALL;
-static bfd_boolean align_targets = TRUE;
-static bfd_boolean warn_unaligned_branch_targets = FALSE;
-static bfd_boolean has_a0_b_retw = FALSE;
-static bfd_boolean workaround_a0_b_retw = FALSE;
-static bfd_boolean workaround_b_j_loop_end = FALSE;
-static bfd_boolean workaround_short_loop = FALSE;
-static bfd_boolean maybe_has_short_loop = FALSE;
-static bfd_boolean workaround_close_loop_end = FALSE;
-static bfd_boolean maybe_has_close_loop_end = FALSE;
-static bfd_boolean enforce_three_byte_loop_align = FALSE;
+static bool align_targets = true;
+static bool warn_unaligned_branch_targets = false;
+static bool has_a0_b_retw = false;
+static bool workaround_a0_b_retw = false;
+static bool workaround_b_j_loop_end = false;
+static bool workaround_short_loop = false;
+static bool maybe_has_short_loop = false;
+static bool workaround_close_loop_end = false;
+static bool maybe_has_close_loop_end = false;
+static bool enforce_three_byte_loop_align = false;
+static bool opt_linkrelax = true;
/* When workaround_short_loops is TRUE, all loops with early exits must
have at least 3 instructions. workaround_all_short_loops is a modifier
workaround_short_loop actions, all straightline loopgtz and loopnez
must have at least 3 instructions. */
-static bfd_boolean workaround_all_short_loops = FALSE;
+static bool workaround_all_short_loops = false;
+/* Generate individual property section for every section.
+ This option is defined in BDF library. */
+extern bool elf32xtensa_separate_props;
+
+/* Xtensa ABI.
+ This option is defined in BDF library. */
+extern int elf32xtensa_abi;
static void
xtensa_setup_hw_workarounds (int earliest, int latest)
/* Enable all workarounds for pre-T1050.0 hardware. */
if (earliest < 105000 || latest < 105000)
{
- workaround_a0_b_retw |= TRUE;
- workaround_b_j_loop_end |= TRUE;
- workaround_short_loop |= TRUE;
- workaround_close_loop_end |= TRUE;
- workaround_all_short_loops |= TRUE;
- enforce_three_byte_loop_align = TRUE;
+ workaround_a0_b_retw |= true;
+ workaround_b_j_loop_end |= true;
+ workaround_short_loop |= true;
+ workaround_close_loop_end |= true;
+ workaround_all_short_loops |= true;
+ enforce_three_byte_loop_align = true;
}
}
option_auto_litpools,
option_no_auto_litpools,
option_auto_litpool_limit,
+
+ option_separate_props,
+ option_no_separate_props,
+
+ option_abi_windowed,
+ option_abi_call0,
};
const char *md_shortopts = "";
{ "no-auto-litpools", no_argument, NULL, option_no_auto_litpools },
{ "auto-litpool-limit", required_argument, NULL, option_auto_litpool_limit },
+ { "separate-prop-tables", no_argument, NULL, option_separate_props },
+
+ { "abi-windowed", no_argument, NULL, option_abi_windowed },
+ { "abi-call0", no_argument, NULL, option_abi_call0 },
+
{ NULL, no_argument, NULL, 0 }
};
as_warn (_("--no-density option is ignored"));
return 1;
case option_link_relax:
- linkrelax = 1;
+ opt_linkrelax = true;
return 1;
case option_no_link_relax:
- linkrelax = 0;
+ opt_linkrelax = false;
return 1;
case option_flix:
produce_flix = FLIX_ALL;
as_warn (_("--no-relax is deprecated; use --no-transform instead"));
return md_parse_option (option_no_transform, arg);
case option_longcalls:
- directive_state[directive_longcalls] = TRUE;
+ directive_state[directive_longcalls] = true;
return 1;
case option_no_longcalls:
- directive_state[directive_longcalls] = FALSE;
+ directive_state[directive_longcalls] = false;
return 1;
case option_text_section_literals:
- use_literal_section = FALSE;
+ use_literal_section = false;
return 1;
case option_no_text_section_literals:
- use_literal_section = TRUE;
+ use_literal_section = true;
return 1;
case option_absolute_literals:
if (!absolute_literals_supported)
as_fatal (_("--absolute-literals option not supported in this Xtensa configuration"));
return 0;
}
- directive_state[directive_absolute_literals] = TRUE;
+ directive_state[directive_absolute_literals] = true;
return 1;
case option_no_absolute_literals:
- directive_state[directive_absolute_literals] = FALSE;
+ directive_state[directive_absolute_literals] = false;
return 1;
case option_workaround_a0_b_retw:
- workaround_a0_b_retw = TRUE;
+ workaround_a0_b_retw = true;
return 1;
case option_no_workaround_a0_b_retw:
- workaround_a0_b_retw = FALSE;
+ workaround_a0_b_retw = false;
return 1;
case option_workaround_b_j_loop_end:
- workaround_b_j_loop_end = TRUE;
+ workaround_b_j_loop_end = true;
return 1;
case option_no_workaround_b_j_loop_end:
- workaround_b_j_loop_end = FALSE;
+ workaround_b_j_loop_end = false;
return 1;
case option_workaround_short_loop:
- workaround_short_loop = TRUE;
+ workaround_short_loop = true;
return 1;
case option_no_workaround_short_loop:
- workaround_short_loop = FALSE;
+ workaround_short_loop = false;
return 1;
case option_workaround_all_short_loops:
- workaround_all_short_loops = TRUE;
+ workaround_all_short_loops = true;
return 1;
case option_no_workaround_all_short_loops:
- workaround_all_short_loops = FALSE;
+ workaround_all_short_loops = false;
return 1;
case option_workaround_close_loop_end:
- workaround_close_loop_end = TRUE;
+ workaround_close_loop_end = true;
return 1;
case option_no_workaround_close_loop_end:
- workaround_close_loop_end = FALSE;
+ workaround_close_loop_end = false;
return 1;
case option_no_workarounds:
- workaround_a0_b_retw = FALSE;
- workaround_b_j_loop_end = FALSE;
- workaround_short_loop = FALSE;
- workaround_all_short_loops = FALSE;
- workaround_close_loop_end = FALSE;
+ workaround_a0_b_retw = false;
+ workaround_b_j_loop_end = false;
+ workaround_short_loop = false;
+ workaround_all_short_loops = false;
+ workaround_close_loop_end = false;
return 1;
case option_align_targets:
- align_targets = TRUE;
+ align_targets = true;
return 1;
case option_no_align_targets:
- align_targets = FALSE;
+ align_targets = false;
return 1;
case option_warn_unaligned_targets:
- warn_unaligned_branch_targets = TRUE;
+ warn_unaligned_branch_targets = true;
return 1;
case option_rename_section_name:
you perform any transformation, always check if transform
is available. If you use the functions we provide for this
purpose, you will be ok. */
- directive_state[directive_transform] = FALSE;
+ directive_state[directive_transform] = false;
return 1;
case option_trampolines:
- use_trampolines = TRUE;
+ use_trampolines = true;
return 1;
case option_no_trampolines:
- use_trampolines = FALSE;
+ use_trampolines = false;
return 1;
case option_auto_litpools:
- auto_litpools = TRUE;
- use_literal_section = FALSE;
+ auto_litpools = true;
+ use_literal_section = false;
+ if (auto_litpool_limit <= 0)
+ auto_litpool_limit = MAX_AUTO_POOL_LITERALS / 2;
return 1;
case option_no_auto_litpools:
- auto_litpools = FALSE;
+ auto_litpools = false;
auto_litpool_limit = -1;
return 1;
if (value < 100 || value > 10000)
as_fatal (_("invalid auto-litpool-limit argument (range is 100-10000)"));
auto_litpool_limit = value;
- auto_litpools = TRUE;
- use_literal_section = FALSE;
+ auto_litpools = true;
+ use_literal_section = false;
return 1;
}
+ case option_separate_props:
+ elf32xtensa_separate_props = true;
+ return 1;
+
+ case option_no_separate_props:
+ elf32xtensa_separate_props = false;
+ return 1;
+
+ case option_abi_windowed:
+ elf32xtensa_abi = XTHAL_ABI_WINDOWED;
+ return 1;
+
+ case option_abi_call0:
+ elf32xtensa_abi = XTHAL_ABI_CALL0;
+ return 1;
+
default:
return 0;
}
--auto-litpool-limit=<value>\n\
(range 100-10000) Maximum number of blocks of\n\
instructions to emit between literal pool\n\
- locations; implies --auto-litpools flag\n", stream);
+ locations; implies --auto-litpools flag\n\
+ --[no-]separate-prop-tables\n\
+ [Do not] place Xtensa property records into\n\
+ individual property sections for each section.\n\
+ Default is to generate single property section.\n", stream);
}
\f
typedef struct state_stackS_struct
{
directiveE directive;
- bfd_boolean negated;
- bfd_boolean old_state;
+ bool negated;
+ bool old_state;
const char *file;
unsigned int line;
const void *datum;
};
-static bfd_boolean
+static bool
use_transform (void)
{
- /* After md_end, you should be checking frag by frag, rather
+ /* After md_finish, you should be checking frag by frag, rather
than state directives. */
- gas_assert (!past_xtensa_end);
+ gas_assert (!past_xtensa_md_finish);
return directive_state[directive_transform];
}
-static bfd_boolean
+static bool
do_align_targets (void)
{
- /* Do not use this function after md_end; just look at align_targets
+ /* Do not use this function after md_finish; just look at align_targets
instead. There is no target-align directive, so alignment is either
enabled for all frags or not done at all. */
- gas_assert (!past_xtensa_end);
+ gas_assert (!past_xtensa_md_finish);
return align_targets && use_transform ();
}
static void
-directive_push (directiveE directive, bfd_boolean negated, const void *datum)
+directive_push (directiveE directive, bool negated, const void *datum)
{
const char *file;
unsigned int line;
static void
directive_pop (directiveE *directive,
- bfd_boolean *negated,
+ bool *negated,
const char **file,
unsigned int *line,
const void **datum)
if (!directive_state_stack)
{
- as_bad (_("unmatched end directive"));
+ as_bad (_("unmatched .end directive"));
*directive = directive_none;
return;
}
while (directive_state_stack)
{
directiveE directive;
- bfd_boolean negated;
+ bool negated;
const char *file;
unsigned int line;
const void *datum;
}
-static bfd_boolean
+static bool
inside_directive (directiveE dir)
{
state_stackS *top = directive_state_stack;
static void
-get_directive (directiveE *directive, bfd_boolean *negated)
+get_directive (directiveE *directive, bool *negated)
{
int len;
unsigned i;
const char *directive_string;
- if (strncmp (input_line_pointer, "no-", 3) != 0)
- *negated = FALSE;
+ if (!startswith (input_line_pointer, "no-"))
+ *negated = false;
else
{
- *negated = TRUE;
+ *negated = true;
input_line_pointer += 3;
}
equivalent to .begin [no-]transform. We should remove it when
we stop accepting those options. */
- if (strncmp (input_line_pointer, "generics", strlen ("generics")) == 0)
+ if (startswith (input_line_pointer, "generics"))
{
as_warn (_("[no-]generics is deprecated; use [no-]transform instead"));
directive_string = "transform";
}
- else if (strncmp (input_line_pointer, "relax", strlen ("relax")) == 0)
+ else if (startswith (input_line_pointer, "relax"))
{
as_warn (_("[no-]relax is deprecated; use [no-]transform instead"));
directive_string = "transform";
xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED)
{
directiveE directive;
- bfd_boolean negated;
+ bool negated;
emit_state *state;
lit_state *ls;
xtensa_end_directive (int ignore ATTRIBUTE_UNUSED)
{
directiveE begin_directive, end_directive;
- bfd_boolean begin_negated, end_negated;
+ bool begin_negated, end_negated;
const char *file;
unsigned int line;
emit_state *state;
emit_state state;
char *p, *base_name;
char c;
- segT dest_seg;
if (inside_directive (directive_literal))
{
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;
-
base_name = input_line_pointer;
xtensa_switch_to_literal_fragment (&state);
- /* ...but if we aren't using text-section-literals, then we
- need to put them in the section we just switched to. */
- if (use_literal_section || directive_state[directive_absolute_literals])
- dest_seg = now_seg;
-
- /* FIXME, despite the previous comments, dest_seg is unused... */
- (void) dest_seg;
-
/* All literals are aligned to four-byte boundaries. */
frag_align (2, 0, 0);
record_alignment (now_seg, 2);
as_bad (_("opcode-specific %s relocation used outside "
"an instruction"), reloc_howto->name);
else if (nbytes != (int) bfd_get_reloc_size (reloc_howto))
- as_bad (_("%s relocations do not fit in %d bytes"),
+ as_bad (ngettext ("%s relocations do not fit in %d byte",
+ "%s relocations do not fit in %d bytes",
+ nbytes),
reloc_howto->name, nbytes);
else if (reloc == BFD_RELOC_XTENSA_TLS_FUNC
|| reloc == BFD_RELOC_XTENSA_TLS_ARG
demand_empty_rest_of_line ();
}
-static bfd_boolean is_leb128_expr;
+static bool is_leb128_expr;
static void
xtensa_leb128 (int sign)
{
- is_leb128_expr = TRUE;
+ is_leb128_expr = true;
s_leb128 (sign);
- is_leb128_expr = FALSE;
+ is_leb128_expr = false;
}
\f
char *str2;
int ch;
int len;
- struct suffix_reloc_map *ptr;
+ unsigned int i;
if (*str++ != '@')
return BFD_RELOC_NONE;
len = str2 - ident;
ch = ident[0];
- for (ptr = &suffix_relocs[0]; ptr->length > 0; ptr++)
- if (ch == ptr->suffix[0]
- && len == ptr->length
- && memcmp (ident, ptr->suffix, ptr->length) == 0)
+ for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++)
+ if (ch == suffix_relocs[i].suffix[0]
+ && len == suffix_relocs[i].length
+ && memcmp (ident, suffix_relocs[i].suffix, suffix_relocs[i].length) == 0)
{
/* Now check for "identifier@suffix+constant". */
if (*str == '-' || *str == '+')
}
*str_p = str;
- return ptr->reloc;
+ return suffix_relocs[i].reloc;
}
return BFD_RELOC_UNUSED;
/* Find the matching operator type. */
-static unsigned char
+static operatorT
map_suffix_reloc_to_operator (bfd_reloc_code_real_type reloc)
{
- struct suffix_reloc_map *sfx;
- unsigned char operator = (unsigned char) -1;
+ operatorT operator = O_illegal;
+ unsigned int i;
- for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++)
+ for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++)
{
- if (sfx->reloc == reloc)
+ if (suffix_relocs[i].reloc == reloc)
{
- operator = sfx->operator;
+ operator = suffix_relocs[i].operator;
break;
}
}
- gas_assert (operator != (unsigned char) -1);
+ gas_assert (operator != O_illegal);
return operator;
}
/* Find the matching reloc type. */
static bfd_reloc_code_real_type
-map_operator_to_reloc (unsigned char operator, bfd_boolean is_literal)
+map_operator_to_reloc (unsigned char operator, bool is_literal)
{
- struct suffix_reloc_map *sfx;
+ unsigned int i;
bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
- for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++)
+ for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++)
{
- if (sfx->operator == operator)
+ if (suffix_relocs[i].operator == operator)
{
- reloc = sfx->reloc;
+ reloc = suffix_relocs[i].reloc;
break;
}
}
tokenize_arguments (char **args, char *str)
{
char *old_input_line_pointer;
- bfd_boolean saw_comma = FALSE;
- bfd_boolean saw_arg = FALSE;
- bfd_boolean saw_colon = FALSE;
+ bool saw_comma = false;
+ bool saw_arg = false;
+ bool saw_colon = false;
int num_args = 0;
char *arg_end, *arg;
int arg_len;
input_line_pointer++;
if (saw_comma || saw_colon || !saw_arg)
goto err;
- saw_colon = TRUE;
+ saw_colon = true;
break;
case ',':
input_line_pointer++;
if (saw_comma || saw_colon || !saw_arg)
goto err;
- saw_comma = TRUE;
+ saw_comma = true;
break;
default:
input_line_pointer = arg_end;
num_args += 1;
- saw_comma = FALSE;
- saw_colon = FALSE;
- saw_arg = TRUE;
+ saw_comma = false;
+ saw_colon = false;
+ saw_arg = true;
break;
}
}
-fini:
+ fini:
if (saw_comma || saw_colon)
goto err;
input_line_pointer = old_input_line_pointer;
return num_args;
-err:
+ err:
if (saw_comma)
as_bad (_("extra comma"));
else if (saw_colon)
/* Parse the arguments to an opcode. Return TRUE on error. */
-static bfd_boolean
+static bool
parse_arguments (TInsn *insn, int num_args, char **arg_strings)
{
expressionS *tok, *last_tok;
xtensa_opcode opcode = insn->opcode;
- bfd_boolean had_error = TRUE;
+ bool had_error = true;
xtensa_isa isa = xtensa_default_isa;
int n, num_regs = 0;
int opcode_operand_count;
goto err;
insn->ntok = tok - insn->tok;
- had_error = FALSE;
+ had_error = false;
err:
input_line_pointer = old_input_line_pointer;
cnt_arg = *cnt_argp;
/* replace the argument with "31-(argument)" */
- new_arg = concat ("31-(", cnt_argp, ")", (char *) NULL);
+ new_arg = concat ("31-(", cnt_arg, ")", (char *) NULL);
free (cnt_arg);
*cnt_argp = new_arg;
xtensa_sysreg sr;
char *opname, *new_opname;
const char *sr_name;
- bfd_boolean has_underbar = FALSE;
+ bool has_underbar = false;
opname = *popname;
if (opname[0] == '_')
{
- has_underbar = TRUE;
+ has_underbar = true;
opname += 1;
}
/* Translate the opcode. */
sr_name = xtensa_sysreg_name (isa, sr);
- new_opname = (char *) xmalloc (strlen (sr_name) + 6);
+ new_opname = XNEWVEC (char, strlen (sr_name) + 6);
sprintf (new_opname, "%s%cur.%s", (has_underbar ? "_" : ""),
opname[0], sr_name);
free (*popname);
xg_translate_idioms (char **popname, int *pnum_args, char **arg_strings)
{
char *opname = *popname;
- bfd_boolean has_underbar = FALSE;
+ bool has_underbar = false;
if (*opname == '_')
{
- has_underbar = TRUE;
+ has_underbar = true;
opname += 1;
}
return 0;
}
+ /* Without an operand, this is given a default immediate operand of 0. */
+ if ((strcmp (opname, "simcall") == 0 && microarch_earliest >= 280000))
+ {
+ if (*pnum_args == 0)
+ {
+ arg_strings[0] = (char *) xmalloc (2);
+ strcpy (arg_strings[0], "0");
+ *pnum_args = 1;
+ }
+ return 0;
+ }
+
if (strcmp (opname, "bbsi.l") == 0)
{
if (xg_check_num_args (pnum_args, 3, opname, arg_strings))
#endif /* TENSILICA_DEBUG */
-static bfd_boolean
+static bool
is_direct_call_opcode (xtensa_opcode opcode)
{
xtensa_isa isa = xtensa_default_isa;
int n, num_operands;
if (xtensa_opcode_is_call (isa, opcode) != 1)
- return FALSE;
+ return false;
num_operands = xtensa_opcode_num_operands (isa, opcode);
for (n = 0; n < num_operands; n++)
{
if (xtensa_operand_is_register (isa, opcode, n) == 0
&& xtensa_operand_is_PCrelative (isa, opcode, n) == 1)
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
Returns non-zero on failure. */
static int
-decode_reloc (bfd_reloc_code_real_type reloc, int *slot, bfd_boolean *is_alt)
+decode_reloc (bfd_reloc_code_real_type reloc, int *slot, bool *is_alt)
{
if (reloc >= BFD_RELOC_XTENSA_SLOT0_OP
&& reloc <= BFD_RELOC_XTENSA_SLOT14_OP)
{
*slot = reloc - BFD_RELOC_XTENSA_SLOT0_OP;
- *is_alt = FALSE;
+ *is_alt = false;
}
else if (reloc >= BFD_RELOC_XTENSA_SLOT0_ALT
&& reloc <= BFD_RELOC_XTENSA_SLOT14_ALT)
{
*slot = reloc - BFD_RELOC_XTENSA_SLOT0_ALT;
- *is_alt = TRUE;
+ *is_alt = true;
}
else
return -1;
when a given option term is true. The meaning of all of the option
terms is given interpretation by this function. */
-static bfd_boolean
+static bool
xg_instruction_matches_option_term (TInsn *insn, const ReqOrOption *option)
{
if (strcmp (option->option_name, "realnop") == 0
- || strncmp (option->option_name, "IsaUse", 6) == 0)
+ || startswith (option->option_name, "IsaUse"))
{
/* These conditions were evaluated statically when building the
relaxation table. There's no need to reevaluate them now. */
- return TRUE;
+ return true;
}
else if (strcmp (option->option_name, "FREEREG") == 0)
return insn->extra_arg.X_op == O_register;
}
-static bfd_boolean
+static bool
xg_instruction_matches_or_options (TInsn *insn,
const ReqOrOptionList *or_option)
{
for (option = or_option; option != NULL; option = option->next)
{
if (xg_instruction_matches_option_term (insn, option))
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
-static bfd_boolean
+static bool
xg_instruction_matches_options (TInsn *insn, const ReqOptionList *options)
{
const ReqOption *req_options;
/* Must match one of the OR clauses. */
if (!xg_instruction_matches_or_options (insn,
req_options->or_option_terms))
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/* Return the transition rule that matches or NULL if none matches. */
-static bfd_boolean
+static bool
xg_instruction_matches_rule (TInsn *insn, TransitionRule *rule)
{
PreconditionList *condition_l;
if (rule->opcode != insn->opcode)
- return FALSE;
+ return false;
for (condition_l = rule->conditions;
condition_l != NULL;
{
case OP_EQUAL:
if (get_expr_const (exp1) != cond->op_data)
- return FALSE;
+ return false;
break;
case OP_NOTEQUAL:
if (get_expr_const (exp1) == cond->op_data)
- return FALSE;
+ return false;
break;
default:
- return FALSE;
+ return false;
}
}
else if (expr_is_register (exp1))
{
case OP_EQUAL:
if (get_expr_register (exp1) != cond->op_data)
- return FALSE;
+ return false;
break;
case OP_NOTEQUAL:
if (get_expr_register (exp1) == cond->op_data)
- return FALSE;
+ return false;
break;
default:
- return FALSE;
+ return false;
}
}
else
- return FALSE;
+ return false;
break;
case OP_OPERAND:
{
case OP_EQUAL:
if (!expr_is_equal (exp1, exp2))
- return FALSE;
+ return false;
break;
case OP_NOTEQUAL:
if (expr_is_equal (exp1, exp2))
- return FALSE;
+ return false;
break;
}
break;
case OP_LITERAL:
case OP_LABEL:
default:
- return FALSE;
+ return false;
}
}
if (!xg_instruction_matches_options (insn, rule->options))
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
static int
transition_rule_cmp (const TransitionRule *a, const TransitionRule *b)
{
- bfd_boolean a_greater = FALSE;
- bfd_boolean b_greater = FALSE;
+ bool a_greater = false;
+ bool b_greater = false;
ReqOptionList *l_a = a->options;
ReqOptionList *l_b = b->options;
&& strcmp (l_or_b->option_name, "IsaUseL32R") == 0)
{
if (prefer_const16)
- a_greater = TRUE;
+ a_greater = true;
else
- b_greater = TRUE;
+ b_greater = true;
}
else if (strcmp (l_or_a->option_name, "IsaUseL32R") == 0
&& strcmp (l_or_b->option_name, "IsaUseConst16") == 0)
{
if (prefer_const16)
- b_greater = TRUE;
+ b_greater = true;
else
- a_greater = TRUE;
+ a_greater = true;
}
else
return 0;
\f
/* Various Other Internal Functions. */
-static bfd_boolean
+static bool
is_unique_insn_expansion (TransitionRule *r)
{
if (!r->to_instr || r->to_instr->next != NULL)
- return FALSE;
+ return false;
if (r->to_instr->typ != INSTR_INSTR)
- return FALSE;
- return TRUE;
+ return false;
+ return true;
}
exclude cases like ADDI being "widened" to an ADDMI, which may
later be relaxed to an ADDMI/ADDI pair. */
-bfd_boolean
-xg_is_single_relaxable_insn (TInsn *insn, TInsn *targ, bfd_boolean narrow_only)
+bool
+xg_is_single_relaxable_insn (TInsn *insn, TInsn *targ, bool narrow_only)
{
TransitionTable *table = xg_build_widen_table (&transition_rule_cmp);
TransitionList *l;
<= xg_get_single_size (rule->to_instr->opcode)))
{
if (match)
- return FALSE;
+ return false;
match = rule;
}
}
if (!match)
- return FALSE;
+ return false;
if (targ)
xg_build_to_insn (targ, insn, match->to_instr);
- return TRUE;
+ return true;
}
}
-static bfd_boolean
+static bool
xg_is_relaxable_insn (TInsn *insn, int lateral_steps)
{
int steps_taken = 0;
if (xg_instruction_matches_rule (insn, rule))
{
if (steps_taken == lateral_steps)
- return TRUE;
+ return true;
steps_taken++;
}
}
- return FALSE;
+ return false;
}
}
-static bfd_boolean
+static bool
xg_valid_literal_expression (const expressionS *exp)
{
switch (exp->X_op)
case O_tlsarg:
case O_tpoff:
case O_dtpoff:
- return TRUE;
+ return true;
default:
- return FALSE;
+ return false;
}
}
/* This will check to see if the value can be converted into the
operand type. It will return TRUE if it does not fit. */
-static bfd_boolean
+static bool
xg_check_operand (int32 value, xtensa_opcode opcode, int operand)
{
uint32 valbuf = value;
if (xtensa_operand_encode (xtensa_default_isa, opcode, operand, &valbuf))
- return TRUE;
- return FALSE;
+ return true;
+ return false;
}
/* Assumes: All immeds are constants. Check that all constants fit
into their immeds; return FALSE if not. */
-static bfd_boolean
+static bool
xg_immeds_fit (const TInsn *insn)
{
xtensa_isa isa = xtensa_default_isa;
case O_register:
case O_constant:
if (xg_check_operand (exp->X_add_number, insn->opcode, i))
- return FALSE;
+ return false;
break;
default:
/* The symbol should have a fixup associated with it. */
- gas_assert (FALSE);
+ gas_assert (false);
break;
}
}
- return TRUE;
+ return true;
}
/* This should only be called after we have an initial
estimate of the addresses. */
-static bfd_boolean
+static bool
xg_symbolic_immeds_fit (const TInsn *insn,
segT pc_seg,
fragS *pc_frag,
case O_register:
case O_constant:
if (xg_check_operand (exp->X_add_number, insn->opcode, i))
- return FALSE;
+ return false;
break;
case O_lo16:
case O_hi16:
/* Check for the worst case. */
if (xg_check_operand (0xffff, insn->opcode, i))
- return FALSE;
+ return false;
break;
case O_symbol:
If pc_frag == 0, then we don't have frag locations yet. */
if (pc_frag == 0
|| xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 0)
- return FALSE;
+ return false;
/* If it is a weak symbol or a symbol in a different section,
it cannot be known to fit at assembly time. */
&& ! pc_frag->tc_frag_data.use_longcalls
&& (! S_IS_WEAK (exp->X_add_symbol)
|| S_IS_DEFINED (exp->X_add_symbol)))
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
symbolP = exp->X_add_symbol;
new_offset = target;
xtensa_operand_do_reloc (isa, insn->opcode, i, &new_offset, pc);
if (xg_check_operand (new_offset, insn->opcode, i))
- return FALSE;
+ return false;
break;
default:
/* The symbol should have a fixup associated with it. */
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
/* Return TRUE on success. */
-static bfd_boolean
+static bool
xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
{
BuildOp *op;
op = bi->ops;
targ->opcode = bi->opcode;
targ->insn_type = ITYPE_INSN;
- targ->is_specific_opcode = FALSE;
+ targ->is_specific_opcode = false;
for (; op != NULL; op = op->next)
{
break;
case OP_FREEREG:
if (insn->extra_arg.X_op != O_register)
- return FALSE;
+ return false;
copy_expr (&targ->tok[op_num], &insn->extra_arg);
break;
case OP_LITERAL:
/* For const16 we can create relocations for these. */
if (targ->opcode == XTENSA_UNDEFINED
|| (targ->opcode != xtensa_const16_opcode))
- return FALSE;
+ return false;
gas_assert (op_data < insn->ntok);
/* Need to build a O_lo16 or O_hi16. */
copy_expr (&targ->tok[op_num], &insn->tok[op_data]);
else if (op->typ == OP_OPERAND_LOW16U)
targ->tok[op_num].X_op = O_lo16;
else
- return FALSE;
+ return false;
}
}
break;
targ->tok[op_num].X_add_number = val;
}
else
- return FALSE; /* We cannot use a relocation for this. */
+ return false; /* We cannot use a relocation for this. */
break;
}
gas_assert (0);
op = bi->ops;
targ->opcode = XTENSA_UNDEFINED;
targ->insn_type = ITYPE_LITERAL;
- targ->is_specific_opcode = FALSE;
+ targ->is_specific_opcode = false;
for (; op != NULL; op = op->next)
{
int op_num = op->op_num;
gas_assert (op_data < insn->ntok);
/* We can only pass resolvable literals through. */
if (!xg_valid_literal_expression (&insn->tok[op_data]))
- return FALSE;
+ return false;
copy_expr (&targ->tok[op_num], &insn->tok[op_data]);
break;
case OP_LITERAL:
op = bi->ops;
targ->opcode = XTENSA_UNDEFINED;
targ->insn_type = ITYPE_LABEL;
- targ->is_specific_opcode = FALSE;
+ targ->is_specific_opcode = false;
/* Literal with no ops is a label? */
gas_assert (op == NULL);
break;
gas_assert (0);
}
- return TRUE;
+ return true;
}
/* Return TRUE on success. */
-static bfd_boolean
+static bool
xg_build_to_stack (IStack *istack, TInsn *insn, BuildInstr *bi)
{
for (; bi != NULL; bi = bi->next)
TInsn *next_insn = istack_push_space (istack);
if (!xg_build_to_insn (next_insn, insn, bi))
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/* Return TRUE on valid expansion. */
-static bfd_boolean
+static bool
xg_expand_to_stack (IStack *istack, TInsn *insn, int lateral_steps)
{
int stack_size = istack->ninsn;
/* This is it. Expand the rule to the stack. */
if (!xg_build_to_stack (istack, insn, rule->to_instr))
- return FALSE;
+ return false;
/* Check to see if it fits. */
for (i = stack_size; i < istack->ninsn; i++)
&& !xg_immeds_fit (tinsn))
{
istack->ninsn = stack_size;
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
steps_taken++;
}
}
- return FALSE;
+ return false;
}
\f
current_insn = *insn;
/* Walk through all of the single instruction expansions. */
- while (xg_is_single_relaxable_insn (¤t_insn, &single_target, FALSE))
+ 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,
enum xtensa_relax_statesE frag_state,
enum xtensa_relax_statesE slot0_state,
int max_growth,
- bfd_boolean is_insn)
+ bool is_insn)
{
/* Finish off this fragment so that it has at LEAST the desired
max_growth. If it doesn't fit in this fragment, close this one
frag_now->fr_opcode = last_insn;
if (is_insn)
- frag_now->tc_frag_data.is_insn = TRUE;
+ frag_now->tc_frag_data.is_insn = true;
frag_var (rs_machine_dependent, max_growth, max_growth,
frag_state, frag_now->fr_symbol, frag_now->fr_offset, last_insn);
/* Return TRUE if the target frag is one of the next non-empty frags. */
-static bfd_boolean
+static bool
is_next_frag_target (const fragS *fragP, const fragS *target)
{
if (fragP == NULL)
- return FALSE;
+ return false;
for (; fragP; fragP = fragP->fr_next)
{
if (fragP == target)
- return TRUE;
+ return true;
if (fragP->fr_fix != 0)
- return FALSE;
+ return false;
if (fragP->fr_type == rs_fill && fragP->fr_offset != 0)
- return FALSE;
+ return false;
if ((fragP->fr_type == rs_align || fragP->fr_type == rs_align_code)
&& ((fragP->fr_address % (1 << fragP->fr_offset)) != 0))
- return FALSE;
+ return false;
if (fragP->fr_type == rs_space)
- return FALSE;
+ return false;
}
- return FALSE;
+ return false;
}
-static bfd_boolean
+static bool
is_branch_jmp_to_next (TInsn *insn, fragS *fragP)
{
xtensa_isa isa = xtensa_default_isa;
if (xtensa_opcode_is_branch (isa, insn->opcode) != 1
&& xtensa_opcode_is_jump (isa, insn->opcode) != 1)
- return FALSE;
+ return false;
for (i = 0; i < num_ops; i++)
{
}
}
if (target_op == -1)
- return FALSE;
+ return false;
if (insn->ntok <= target_op)
- return FALSE;
+ return false;
if (insn->tok[target_op].X_op != O_symbol)
- return FALSE;
+ return false;
sym = insn->tok[target_op].X_add_symbol;
if (sym == NULL)
- return FALSE;
+ return false;
if (insn->tok[target_op].X_add_number != 0)
- return FALSE;
+ return false;
target_frag = symbol_get_frag (sym);
if (target_frag == NULL)
- return FALSE;
+ return false;
if (is_next_frag_target (fragP->fr_next, target_frag)
&& S_GET_VALUE (sym) == target_frag->fr_address)
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
int i = 1;
if (xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 1
&& insn->tok[i].X_op == O_symbol)
- symbol_get_tc (insn->tok[i].X_add_symbol)->is_loop_target = TRUE;
+ symbol_get_tc (insn->tok[i].X_add_symbol)->is_loop_target = true;
return;
}
&& insn->tok[i].X_op == O_symbol)
{
symbolS *sym = insn->tok[i].X_add_symbol;
- symbol_get_tc (sym)->is_branch_target = TRUE;
+ symbol_get_tc (sym)->is_branch_target = true;
if (S_IS_DEFINED (sym))
- symbol_get_frag (sym)->tc_frag_data.is_branch_target = TRUE;
+ symbol_get_frag (sym)->tc_frag_data.is_branch_target = true;
}
}
}
/* Return FALSE if no error. */
-static bfd_boolean
+static bool
xg_build_token_insn (BuildInstr *instr_spec, TInsn *old_insn, TInsn *new_insn)
{
int num_ops = 0;
case INSTR_LABEL_DEF:
abort ();
}
- new_insn->is_specific_opcode = FALSE;
+ new_insn->is_specific_opcode = false;
new_insn->debug_line = old_insn->debug_line;
new_insn->loc_directive_seen = old_insn->loc_directive_seen;
}
new_insn->ntok = num_ops;
- return FALSE;
+ return false;
}
/* Return TRUE if it was simplified. */
-static bfd_boolean
+static bool
xg_simplify_insn (TInsn *old_insn, TInsn *new_insn)
{
TransitionRule *rule;
BuildInstr *insn_spec;
if (old_insn->is_specific_opcode || !density_supported)
- return FALSE;
+ return false;
rule = xg_instruction_match (old_insn);
if (rule == NULL)
- return FALSE;
+ return false;
insn_spec = rule->to_instr;
/* There should only be one. */
gas_assert (insn_spec != NULL);
gas_assert (insn_spec->next == NULL);
if (insn_spec->next != NULL)
- return FALSE;
+ return false;
xg_build_token_insn (insn_spec, old_insn, new_insn);
- return TRUE;
+ return true;
}
tokens into the stack or relax it and place multiple
instructions/literals onto the stack. Return FALSE if no error. */
-static bfd_boolean
+static bool
xg_expand_assembly_insn (IStack *istack, TInsn *orig_insn)
{
int noperands;
TInsn new_insn;
- bfd_boolean do_expand;
+ bool do_expand;
tinsn_init (&new_insn);
orig_insn->opcode);
if (orig_insn->ntok < noperands)
{
- as_bad (_("found %d operands for '%s': Expected %d"),
+ as_bad (ngettext ("found %d operand for '%s': Expected %d",
+ "found %d operands for '%s': Expected %d",
+ orig_insn->ntok),
orig_insn->ntok,
xtensa_opcode_name (xtensa_default_isa, orig_insn->opcode),
noperands);
- return TRUE;
+ return true;
}
if (orig_insn->ntok > noperands)
- as_warn (_("found too many (%d) operands for '%s': Expected %d"),
+ as_warn (ngettext ("found %d operand for '%s': Expected %d",
+ "found %d operands for '%s': Expected %d",
+ orig_insn->ntok),
orig_insn->ntok,
xtensa_opcode_name (xtensa_default_isa, orig_insn->opcode),
noperands);
orig_insn->ntok = noperands;
if (tinsn_has_invalid_symbolic_operands (orig_insn))
- return TRUE;
+ return true;
/* Special case for extui opcode which has constraints not handled
by the ordinary operand encoding checks. The number of operands
if (shiftimm + maskimm > 32)
{
as_bad (_("immediate operands sum to greater than 32"));
- return TRUE;
+ return true;
}
}
so that the assembly scheduler will keep the L32R/CALLX instructions
adjacent. */
if (is_direct_call_opcode (orig_insn->opcode))
- do_expand = FALSE;
+ do_expand = false;
if (tinsn_has_symbolic_operands (orig_insn))
{
now if an operand is "complex" (e.g., difference of symbols) and
will have to be stored as a literal regardless of the value. */
if (!tinsn_has_complex_operands (orig_insn))
- do_expand = FALSE;
+ do_expand = false;
}
else if (xg_immeds_fit (orig_insn))
- do_expand = FALSE;
+ do_expand = false;
if (do_expand)
xg_assembly_relax (istack, orig_insn, 0, 0, 0, 0, 0);
else
istack_push (istack, orig_insn);
- return FALSE;
+ return false;
}
static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
-static bfd_boolean
+static bool
get_is_linkonce_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec)
{
flagword flags, link_once_flags;
- flags = bfd_get_section_flags (abfd, sec);
+ flags = bfd_section_flags (sec);
link_once_flags = (flags & SEC_LINK_ONCE);
/* Flags might not be set yet. */
symbol will be in the output file. */
if (get_is_linkonce_section (stdoutput, sec))
{
- symbolP = symbol_new (name, sec, 0, frag);
+ symbolP = symbol_new (name, sec, frag, 0);
S_CLEAR_EXTERNAL (symbolP);
/* symbolP->local = 1; */
}
else
- symbolP = symbol_new (name, sec, 0, frag);
+ symbolP = symbol_new (name, sec, frag, 0);
xtensa_add_literal_sym (symbolP);
emit_state state;
symbolS *lit_sym = NULL;
bfd_reloc_code_real_type reloc;
- bfd_boolean pcrel = FALSE;
+ bool pcrel = false;
char *p;
/* size = 4 for L32R. It could easily be larger when we move to
switch (emit_val->X_op)
{
case O_pcrel:
- pcrel = TRUE;
+ pcrel = true;
/* fall through */
case O_pltrel:
case O_tlsfunc:
case O_dtpoff:
p = frag_more (litsize);
xtensa_set_frag_assembly_state (frag_now);
- reloc = map_operator_to_reloc (emit_val->X_op, TRUE);
+ reloc = map_operator_to_reloc (emit_val->X_op, true);
if (emit_val->X_add_symbol)
emit_val->X_op = O_symbol;
else
lit_saved_frag = frag_now;
frag_now->tc_frag_data.literal_frag = get_literal_pool_location (now_seg);
frag_now->fr_symbol = xtensa_create_literal_symbol (now_seg, frag_now);
- xg_finish_frag (0, RELAX_LITERAL, 0, size, FALSE);
+ xg_finish_frag (0, RELAX_LITERAL, 0, size, false);
/* Go back. */
xtensa_restore_emit_state (&state);
/* Put in a fixup record based on the opcode.
Return TRUE on success. */
-static bfd_boolean
+static bool
xg_add_opcode_fix (TInsn *tinsn,
int opnum,
xtensa_format fmt,
{
as_bad (_("invalid relocation for operand %i of '%s'"),
opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
- return FALSE;
+ return false;
}
/* Handle erroneous "@h" and "@l" expressions here before they propagate
{
as_bad (_("invalid expression for operand %i of '%s'"),
opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
- return FALSE;
+ return false;
}
/* Next try the generic relocs. */
if (reloc == BFD_RELOC_NONE)
{
as_bad (_("invalid relocation in instruction slot %i"), slot);
- return FALSE;
+ return false;
}
howto = bfd_reloc_type_lookup (stdoutput, reloc);
{
as_bad (_("undefined symbol for opcode \"%s\""),
xtensa_opcode_name (xtensa_default_isa, opcode));
- return FALSE;
+ return false;
}
fmt_length = xtensa_format_length (xtensa_default_isa, fmt);
the_fix->tc_fix_data.X_add_number = exp->X_add_number;
the_fix->tc_fix_data.slot = slot;
- return TRUE;
+ return true;
}
-static bfd_boolean
+static bool
xg_emit_insn_to_buf (TInsn *tinsn,
char *buf,
fragS *fragP,
offsetT offset,
- bfd_boolean build_fix)
+ bool build_fix)
{
static xtensa_insnbuf insnbuf = NULL;
- bfd_boolean has_symbolic_immed = FALSE;
- bfd_boolean ok = TRUE;
+ bool has_symbolic_immed = false;
+ bool ok = true;
if (!insnbuf)
insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
expressionS *exp = &tinsn->tok[opnum];
if (!xg_add_opcode_fix (tinsn, opnum, fmt, slot, exp, fragP, offset))
- ok = FALSE;
+ ok = false;
}
- fragP->tc_frag_data.is_insn = TRUE;
+ fragP->tc_frag_data.is_insn = true;
xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf,
(unsigned char *) buf, 0);
return ok;
/* Return TRUE if the instruction can write to the specified
integer register. */
-static bfd_boolean
+static bool
is_register_writer (const TInsn *insn, const char *regset, int regnum)
{
int i;
{
if ((insn->tok[i].X_op == O_register)
&& (insn->tok[i].X_add_number == regnum))
- return TRUE;
+ return true;
}
}
}
- return FALSE;
+ return false;
}
-static bfd_boolean
+static bool
is_bad_loopend_opcode (const TInsn *tinsn)
{
xtensa_opcode opcode = tinsn->opcode;
if (opcode == XTENSA_UNDEFINED)
- return FALSE;
+ return false;
if (opcode == xtensa_call0_opcode
|| opcode == xtensa_callx0_opcode
|| opcode == xtensa_retw_n_opcode
|| opcode == xtensa_waiti_opcode
|| opcode == xtensa_rsr_lcount_opcode)
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
Also, the assembler generates stabs labels that need
not be aligned: FAKE_LABEL_NAME . {"F", "L", "endfunc"}. */
-static bfd_boolean
+static bool
is_unaligned_label (symbolS *sym)
{
const char *name = S_GET_NAME (sym);
if (name
&& name[0] == '.'
&& name[1] == 'L' && (name[2] == 'n' || name[2] == 'M'))
- return TRUE;
+ return true;
/* FAKE_LABEL_NAME followed by "F", "L" or "endfunc" */
if (fake_size == 0)
&& (name[fake_size] == 'F'
|| name[fake_size] == 'L'
|| (name[fake_size] == 'e'
- && strncmp ("endfunc", name+fake_size, 7) == 0)))
- return TRUE;
+ && startswith (name + fake_size, "endfunc"))))
+ return true;
- return FALSE;
+ return false;
}
}
-static bfd_boolean
+static bool
next_frag_opcode_is_loop (const fragS *fragP, xtensa_opcode *opcode)
{
xtensa_opcode out_opcode;
const fragS *next_fragP = next_non_empty_frag (fragP);
if (next_fragP == NULL)
- return FALSE;
+ return false;
out_opcode = get_opcode_from_buf (next_fragP->fr_literal, 0);
if (xtensa_opcode_is_loop (xtensa_default_isa, out_opcode) == 1)
{
*opcode = out_opcode;
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
}
-static bfd_boolean
+static bool
next_frag_is_branch_target (const fragS *fragP)
{
/* Sometimes an empty will end up here due to storage allocation issues,
for (fragP = fragP->fr_next; fragP; fragP = fragP->fr_next)
{
if (fragP->tc_frag_data.is_branch_target)
- return TRUE;
+ return true;
if (fragP->fr_fix != 0)
break;
}
- return FALSE;
+ return false;
}
-static bfd_boolean
+static bool
next_frag_is_loop_target (const fragS *fragP)
{
/* Sometimes an empty will end up here due storage allocation issues.
for (fragP = fragP->fr_next; fragP; fragP = fragP->fr_next)
{
if (fragP->tc_frag_data.is_loop_target)
- return TRUE;
+ return true;
if (fragP->fr_fix != 0)
break;
}
- return FALSE;
+ return false;
}
{
/* Any labels pointing to the current location need
to be adjusted to after the literal pool. */
- emit_state s;
fragS *pool_location;
if (use_literal_section)
frag_now->tc_frag_data.lit_frchain = frchain_now;
frag_now->tc_frag_data.literal_frag = frag_now;
/* Just record this frag. */
- xtensa_maybe_create_literal_pool_frag (FALSE, FALSE);
+ xtensa_maybe_create_literal_pool_frag (false, false);
frag_variant (rs_machine_dependent, 0, 0,
RELAX_LITERAL_POOL_BEGIN, NULL, 0, NULL);
xtensa_set_frag_assembly_state (frag_now);
RELAX_LITERAL_POOL_END, NULL, 0, NULL);
xtensa_set_frag_assembly_state (frag_now);
- /* Now put a frag into the literal pool that points to this location. */
set_literal_pool_location (now_seg, pool_location);
- xtensa_switch_to_non_abs_literal_fragment (&s);
- frag_align (2, 0, 0);
- record_alignment (now_seg, 2);
-
- /* Close whatever frag is there. */
- frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- frag_now->tc_frag_data.literal_frag = pool_location;
- frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
- xtensa_restore_emit_state (&s);
- xtensa_set_frag_assembly_state (frag_now);
}
static fragS *
get_literal_pool_location (segT seg)
{
- struct litpool_seg *lps = litpool_seg_list.next;
- struct litpool_frag *lpf;
- for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
- ;
- if (lps)
+ if (auto_litpools)
{
- for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
- { /* Skip "candidates" for now. */
- if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
- lpf->priority == 1)
- return lpf->fragP;
- }
- /* Must convert a lower-priority pool. */
- for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
- {
- if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
- return lpf->fragP;
- }
- /* Still no match -- try for a low priority pool. */
- for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
+ struct litpool_seg *lps = litpool_seg_list.next;
+ struct litpool_frag *lpf;
+ for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
+ ;
+ if (lps)
{
- if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
- return lpf->fragP;
+ for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
+ { /* Skip "candidates" for now. */
+ if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
+ lpf->priority == 1)
+ return lpf->fragP;
+ }
+ /* Must convert a lower-priority pool. */
+ for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
+ {
+ if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
+ return lpf->fragP;
+ }
+ /* Still no match -- try for a low priority pool. */
+ for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
+ {
+ if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+ return lpf->fragP;
+ }
}
}
return seg_info (seg)->tc_segment_info_data.literal_pool_loc;
xtensa_set_frag_assembly_state (fragS *fragP)
{
if (!density_supported)
- fragP->tc_frag_data.is_no_density = TRUE;
+ 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_md_finish, so we can't use "use_transform" or
"use_schedule" here. */
if (!directive_state[directive_transform])
- fragP->tc_frag_data.is_no_transform = TRUE;
+ fragP->tc_frag_data.is_no_transform = true;
if (directive_state[directive_longcalls])
- fragP->tc_frag_data.use_longcalls = TRUE;
+ fragP->tc_frag_data.use_longcalls = true;
fragP->tc_frag_data.use_absolute_literals =
directive_state[directive_absolute_literals];
- fragP->tc_frag_data.is_assembly_state_set = TRUE;
+ fragP->tc_frag_data.is_assembly_state_set = true;
}
-static bfd_boolean
+static bool
relaxable_section (asection *sec)
{
return ((sec->flags & SEC_DEBUGGING) == 0
segment_info_type *seginfo;
fragS *fragP;
flagword flags;
- flags = bfd_get_section_flags (stdoutput, sec);
+ flags = bfd_section_flags (sec);
if (flags & SEC_DEBUGGING)
continue;
if (!(flags & SEC_ALLOC))
{
while (last_fragP != fragP->fr_next)
{
- last_fragP->tc_frag_data.is_no_transform = TRUE;
+ last_fragP->tc_frag_data.is_no_transform = true;
last_fragP = last_fragP->fr_next;
}
}
segment_info_type *seginfo;
fragS *fragP;
flagword flags;
- flags = bfd_get_section_flags (stdoutput, sec);
+ flags = bfd_section_flags (sec);
if (flags & SEC_DEBUGGING)
continue;
if (!(flags & SEC_ALLOC))
}
else
{
- fragP->tc_frag_data.is_assembly_state_set = TRUE;
+ fragP->tc_frag_data.is_assembly_state_set = true;
fragP->tc_frag_data.is_no_density =
last_fragP->tc_frag_data.is_no_density;
fragP->tc_frag_data.is_no_transform =
asection *sec,
void *unused ATTRIBUTE_UNUSED)
{
- flagword flags = bfd_get_section_flags (abfd, sec);
+ flagword flags = bfd_section_flags (sec);
segment_info_type *seginfo = seg_info (sec);
fragS *frag = seginfo->frchainP->frch_root;
asection *sec,
void *unused ATTRIBUTE_UNUSED)
{
- flagword flags = bfd_get_section_flags (abfd, sec);
+ flagword flags = bfd_section_flags (sec);
segment_info_type *seginfo = seg_info (sec);
fragS *frag = seginfo->frchainP->frch_root;
xtensa_isa isa = xtensa_default_isa;
static xtensa_insnbuf slotbuf = NULL;
xtensa_format fmt;
int slot;
- bfd_boolean alt_reloc;
+ bool alt_reloc;
xtensa_opcode opcode;
char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
number_to_chars_littleendian (buf, val, n);
}
+static void
+xg_init_global_config (void)
+{
+ target_big_endian = XCHAL_HAVE_BE;
+
+ density_supported = XCHAL_HAVE_DENSITY;
+ absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS;
+ xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH;
+
+ directive_state[directive_density] = XCHAL_HAVE_DENSITY;
+ directive_state[directive_absolute_literals] = XSHAL_USE_ABSOLUTE_LITERALS;
+
+ microarch_earliest = XTENSA_MARCH_EARLIEST;
+}
+
+void
+xtensa_init (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+ xg_init_global_config ();
+}
/* This function is called once, at assembler startup time. It should
set up all the tables, etc. that the MD part of the assembler will
xtensa_default_isa = xtensa_isa_init (0, 0);
isa = xtensa_default_isa;
- linkrelax = 1;
+ linkrelax = opt_linkrelax;
/* Set up the literal sections. */
memset (&default_lit_sections, 0, sizeof (default_lit_sections));
/* Set up the assembly state. */
if (!frag_now->tc_frag_data.is_assembly_state_set)
xtensa_set_frag_assembly_state (frag_now);
+
+ if (!use_literal_section)
+ xtensa_mark_literal_pool_location ();
}
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;
+ 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;
+ symbol_get_frag (sym)->tc_frag_data.is_loop_target = true;
dwarf2_emit_label (sym);
}
frag_new (0);
xtensa_set_frag_assembly_state (frag_now);
}
- frag_now->tc_frag_data.is_insn = FALSE;
+ frag_now->tc_frag_data.is_insn = false;
xtensa_clear_insn_labels ();
}
xtensa_isa isa = xtensa_default_isa;
char *opname;
unsigned opnamelen;
- bfd_boolean has_underbar = FALSE;
+ bool has_underbar = false;
char *arg_strings[MAX_INSN_ARGS];
int num_args;
TInsn orig_insn; /* Original instruction from the input. */
/* Check for an underbar prefix. */
if (*opname == '_')
{
- has_underbar = TRUE;
+ has_underbar = true;
opname += 1;
}
orig_insn.is_specific_opcode = (has_underbar || !use_transform ());
orig_insn.opcode = xtensa_opcode_lookup (isa, opname);
- /* Special case: Check for "CALLXn.TLS" psuedo op. If found, grab its
+ /* Special case: Check for "CALLXn.TLS" pseudo op. If found, grab its
extra argument and set the opcode to "CALLXn". */
if (orig_insn.opcode == XTENSA_UNDEFINED
&& strncasecmp (opname, "callx", 5) == 0)
}
}
- /* Special case: Check for "j.l" psuedo op. */
+ /* Special case: Check for "j.l" pseudo op. */
if (orig_insn.opcode == XTENSA_UNDEFINED
&& strncasecmp (opname, "j.l", 3) == 0)
{
&& fragP->fr_offset > 0
&& now_seg != bss_section)
{
- fragP->tc_frag_data.is_align = TRUE;
+ fragP->tc_frag_data.is_align = true;
fragP->tc_frag_data.alignment = fragP->fr_offset;
}
int slot;
xtensa_isa isa = xtensa_default_isa;
valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
- bfd_boolean alt_reloc;
+ bool alt_reloc;
if (fixP->fx_r_type == BFD_RELOC_XTENSA_ASM_EXPAND)
return 0;
nearest macro to where the check needs to take place. FIXME: This
seems wrong. */
-bfd_boolean
+bool
xtensa_check_inside_bundle (void)
{
if (cur_vinsn.inside_bundle && input_line_pointer[-1] == '.')
/* This function must always return FALSE because it is called via a
macro that has nothing to do with bundling. */
- return FALSE;
+ return false;
}
/* Set up the assembly state. */
if (!frag_now->tc_frag_data.is_assembly_state_set)
xtensa_set_frag_assembly_state (frag_now);
+
+ if (!use_literal_section
+ && seg_info (now_seg)->tc_segment_info_data.literal_pool_loc == NULL
+ && !xtensa_is_init_fini (now_seg))
+ xtensa_mark_literal_pool_location ();
}
/* tc_fix_adjustable hook */
-bfd_boolean
+bool
xtensa_fix_adjustable (fixS *fixP)
{
/* We need the symbol name for the VTABLE entries. */
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"));
+ as_bad_subtract (fixP);
switch (fixP->fx_r_type)
{
case BFD_RELOC_8:
if (fixP->fx_subsy)
{
+ bool neg = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
+ < S_GET_VALUE (fixP->fx_subsy));
+
switch (fixP->fx_r_type)
{
case BFD_RELOC_8:
- fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
+ fixP->fx_r_type = neg
+ ? BFD_RELOC_XTENSA_NDIFF8 : BFD_RELOC_XTENSA_PDIFF8;
fixP->fx_signed = 0;
break;
case BFD_RELOC_16:
- fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
+ fixP->fx_r_type = neg
+ ? BFD_RELOC_XTENSA_NDIFF16 : BFD_RELOC_XTENSA_PDIFF16;
fixP->fx_signed = 0;
break;
case BFD_RELOC_32:
- fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
+ fixP->fx_r_type = neg
+ ? BFD_RELOC_XTENSA_NDIFF32 : BFD_RELOC_XTENSA_PDIFF32;
fixP->fx_signed = 0;
break;
default:
val = *valP;
fixP->fx_done = 1;
}
+ else if (S_GET_SEGMENT (fixP->fx_addsy) == absolute_section)
+ {
+ val = S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset;
+ *valP = val;
+ fixP->fx_done = 1;
+ }
/* fall through */
case BFD_RELOC_XTENSA_PLT:
rt->opcode_unit_use = ouuf;
rt->opcode_unit_stage = ousf;
- rt->units = (unsigned char **) xcalloc (cycles, sizeof (unsigned char *));
+ rt->units = XCNEWVEC (unsigned char *, cycles);
for (i = 0; i < cycles; i++)
- rt->units[i] = (unsigned char *) xcalloc (nu, sizeof (unsigned char));
+ rt->units[i] = XCNEWVEC (unsigned char, nu);
return rt;
}
for (i = 0; i < old_cycles; i++)
rt->units[i] = XRESIZEVEC (unsigned char, rt->units[i], rt->num_units);
for (i = old_cycles; i < cycles; i++)
- rt->units[i] = xcalloc (rt->num_units, sizeof (unsigned char));
+ rt->units[i] = XCNEWVEC (unsigned char, rt->num_units);
}
-bfd_boolean
+bool
resources_available (resource_table *rt, xtensa_opcode opcode, int cycle)
{
int i;
int copies_in_use = rt->units[stage + cycle][unit];
int copies = (rt->unit_num_copies) (rt->data, unit);
if (copies_in_use >= copies)
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
write the same state, or access the same tieports. That is
checked by check_t1_t2_reads_and_writes. */
-static bfd_boolean
+static bool
resources_conflict (vliw_insn *vinsn)
{
int i;
/* This is the most common case by far. Optimize it. */
if (vinsn->num_slots == 1)
- return FALSE;
+ return false;
if (rt == NULL)
{
for (i = 0; i < vinsn->num_slots; i++)
{
if (!resources_available (rt, vinsn->slots[i].opcode, 0))
- return TRUE;
+ return true;
reserve_resources (rt, vinsn->slots[i].opcode, 0);
}
- return FALSE;
+ return false;
}
\f
/* finish_vinsn, emit_single_op and helper functions. */
-static bfd_boolean find_vinsn_conflicts (vliw_insn *);
+static bool find_vinsn_conflicts (vliw_insn *);
static xtensa_format xg_find_narrowest_format (vliw_insn *);
static void xg_assemble_vliw_tokens (vliw_insn *);
{
IStack slotstack;
int i;
+ int slots;
if (find_vinsn_conflicts (vinsn))
{
if (vinsn->format == XTENSA_UNDEFINED)
vinsn->format = xg_find_narrowest_format (vinsn);
- if (xtensa_format_num_slots (xtensa_default_isa, vinsn->format) > 1
+ slots = xtensa_format_num_slots (xtensa_default_isa, vinsn->format);
+ if (slots > 1
&& produce_flix == FLIX_NONE)
{
as_bad (_("The option \"--no-allow-flix\" prohibits multi-slot flix."));
return;
}
- if (vinsn->num_slots
- != xtensa_format_num_slots (xtensa_default_isa, vinsn->format))
+ if (vinsn->num_slots != slots)
{
- as_bad (_("format '%s' allows %d slots, but there are %d opcodes"),
+ as_bad (_("mismatch for format '%s': #slots = %d, #opcodes = %d"),
xtensa_format_name (xtensa_default_isa, vinsn->format),
- xtensa_format_num_slots (xtensa_default_isa, vinsn->format),
- vinsn->num_slots);
+ slots, vinsn->num_slots);
xg_clear_vinsn (vinsn);
return;
}
{
symbolS *lit_sym = NULL;
int j;
- bfd_boolean e = FALSE;
- bfd_boolean saved_density = density_supported;
+ bool e = false;
+ bool saved_density = density_supported;
/* We don't want to narrow ops inside multi-slot bundles. */
if (vinsn->num_slots > 1)
- density_supported = FALSE;
+ density_supported = false;
istack_init (&slotstack);
if (vinsn->slots[i].opcode == xtensa_nop_opcode)
if (xg_expand_assembly_insn (&slotstack, &vinsn->slots[i]))
{
- e = TRUE;
+ e = true;
continue;
}
static char check_t1_t2_reads_and_writes (TInsn *, TInsn *);
-static bfd_boolean
+static bool
find_vinsn_conflicts (vliw_insn *vinsn)
{
int i, j;
int branches = 0;
xtensa_isa isa = xtensa_default_isa;
- gas_assert (!past_xtensa_end);
+ gas_assert (!past_xtensa_md_finish);
for (i = 0 ; i < vinsn->num_slots; i++)
{
TInsn *op1 = &vinsn->slots[i];
if (op1->is_specific_opcode)
- op1->keep_wide = TRUE;
+ op1->keep_wide = true;
else
- op1->keep_wide = FALSE;
+ op1->keep_wide = false;
}
for (i = 0 ; i < vinsn->num_slots; i++)
as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same register"),
xtensa_opcode_name (isa, op1->opcode), i,
xtensa_opcode_name (isa, op2->opcode), j);
- return TRUE;
+ return true;
case 'd':
as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same state"),
xtensa_opcode_name (isa, op1->opcode), i,
xtensa_opcode_name (isa, op2->opcode), j);
- return TRUE;
+ return true;
case 'e':
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;
+ return true;
case 'f':
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;
+ return true;
default:
/* Everything is OK. */
break;
if (branches > 1)
{
as_bad (_("multiple branches or jumps in the same bundle"));
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
int t2_states;
int t1_interfaces;
int t2_interfaces;
- bfd_boolean t1_volatile = FALSE;
- bfd_boolean t2_volatile = FALSE;
+ bool t1_volatile = false;
+ bool t2_volatile = false;
/* Check registers. */
for (j = 0; j < t2->ntok; j++)
t2_inout = xtensa_interface_inout (isa, t2_int);
if (xtensa_interface_has_side_effect (isa, t2_int) == 1)
- t2_volatile = TRUE;
+ t2_volatile = true;
for (i = 0; i < t1_interfaces; i++)
{
t1_inout = xtensa_interface_inout (isa, t1_int);
if (xtensa_interface_has_side_effect (isa, t1_int) == 1)
- t1_volatile = TRUE;
+ t1_volatile = true;
if (t1_volatile && t2_volatile && (t1_class == t2_class))
return 'f';
if (!v_copy.slots[slot].keep_wide
&& !v_copy.slots[slot].is_specific_opcode
&& xg_is_single_relaxable_insn (&v_copy.slots[slot],
- &widened, TRUE)
+ &widened, true)
&& opcode_fits_format_slot (widened.opcode,
format, slot))
{
each tinsn in the vinsn. */
static int
-relaxation_requirements (vliw_insn *vinsn, bfd_boolean *pfinish_frag)
+relaxation_requirements (vliw_insn *vinsn, bool *pfinish_frag)
{
- bfd_boolean finish_frag = FALSE;
+ bool finish_frag = false;
int extra_space = 0;
int slot;
{
/* A narrow instruction could be widened later to help
alignment issues. */
- if (xg_is_single_relaxable_insn (tinsn, 0, TRUE)
+ if (xg_is_single_relaxable_insn (tinsn, 0, true)
&& !tinsn->is_specific_opcode
&& vinsn->num_slots == 1)
{
{
/* A fix record will be added for this instruction prior
to relaxation, so make it end the frag. */
- finish_frag = TRUE;
+ finish_frag = true;
}
}
}
}
-static bfd_boolean
+static bool
emit_single_op (TInsn *orig_insn)
{
int i;
xg_assembly_relax (&istack, orig_insn, now_seg, frag_now, 0, 1, 0);
else
if (xg_expand_assembly_insn (&istack, orig_insn))
- return TRUE;
+ return true;
for (i = 0; i < istack.ninsn; i++)
{
break;
}
}
- return FALSE;
+ return false;
}
static void
xg_assemble_vliw_tokens (vliw_insn *vinsn)
{
- bfd_boolean finish_frag;
- bfd_boolean is_jump = FALSE;
- bfd_boolean is_branch = FALSE;
+ bool finish_frag;
+ bool is_jump = false;
+ bool is_branch = false;
xtensa_isa isa = xtensa_default_isa;
int insn_size;
int extra_space;
char *f = NULL;
int slot;
struct dwarf2_line_info debug_line;
- bfd_boolean loc_directive_seen = FALSE;
+ bool loc_directive_seen = false;
TInsn *tinsn;
memset (&debug_line, 0, sizeof (struct dwarf2_line_info));
&& xtensa_opcode_is_branch (isa, vinsn->slots[0].opcode) == 1
&& use_transform ())
{
- has_a0_b_retw = TRUE;
+ has_a0_b_retw = true;
/* Mark this fragment with the special RELAX_ADD_NOP_IF_A0_B_RETW.
After the first assembly pass we will check all of them and
add a nop if needed. */
- frag_now->tc_frag_data.is_insn = TRUE;
+ frag_now->tc_frag_data.is_insn = true;
frag_var (rs_machine_dependent, 4, 4,
RELAX_ADD_NOP_IF_A0_B_RETW,
frag_now->fr_symbol,
frag_now->fr_offset,
NULL);
xtensa_set_frag_assembly_state (frag_now);
- frag_now->tc_frag_data.is_insn = TRUE;
+ frag_now->tc_frag_data.is_insn = true;
frag_var (rs_machine_dependent, 4, 4,
RELAX_ADD_NOP_IF_A0_B_RETW,
frag_now->fr_symbol,
|| tinsn->debug_line.column < debug_line.column))
debug_line = tinsn->debug_line;
if (tinsn->loc_directive_seen)
- loc_directive_seen = TRUE;
+ loc_directive_seen = true;
}
/* Special cases for instructions that force an alignment... */
target_sym = vinsn->slots[0].tok[1].X_add_symbol;
xtensa_set_frag_assembly_state (frag_now);
- frag_now->tc_frag_data.is_insn = TRUE;
+ 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);
+ true, frag_now->tc_frag_data.is_no_density);
if (use_transform ())
frag_var (rs_machine_dependent, max_fill, max_fill,
is_bad_loopend_opcode (&vinsn->slots[0]));
}
else
- set_last_insn_flags (now_seg, now_subseg, FLAG_IS_BAD_LOOPEND, FALSE);
+ set_last_insn_flags (now_seg, now_subseg, FLAG_IS_BAD_LOOPEND, false);
insn_size = xtensa_format_length (isa, vinsn->format);
{
f = frag_more (insn_size + extra_space);
xtensa_set_frag_assembly_state (frag_now);
- frag_now->tc_frag_data.is_insn = TRUE;
+ frag_now->tc_frag_data.is_insn = true;
}
- vinsn_to_insnbuf (vinsn, f, frag_now, FALSE);
+ vinsn_to_insnbuf (vinsn, f, frag_now, false);
if (vinsn->format == XTENSA_UNDEFINED)
return;
frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset;
frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag;
if (tinsn->opcode == xtensa_l32r_opcode)
- {
- frag_now->tc_frag_data.literal_frags[slot] =
- tinsn->tok[1].X_add_symbol->sy_frag;
- }
+ frag_now->tc_frag_data.literal_frags[slot]
+ = symbol_get_frag (tinsn->tok[1].X_add_symbol);
if (tinsn->literal_space != 0)
xg_assemble_literal_space (tinsn->literal_space, slot);
frag_now->tc_frag_data.free_reg[slot] = tinsn->extra_arg;
if (tinsn->subtype == RELAX_NARROW)
gas_assert (vinsn->num_slots == 1);
if (xtensa_opcode_is_jump (isa, tinsn->opcode) == 1)
- is_jump = TRUE;
+ is_jump = true;
if (xtensa_opcode_is_branch (isa, tinsn->opcode) == 1)
- is_branch = TRUE;
+ is_branch = true;
if (tinsn->subtype || tinsn->symbol || tinsn->offset
|| tinsn->literal_frag || is_jump || is_branch)
- finish_frag = TRUE;
+ finish_frag = true;
}
if (vinsn_has_specific_opcodes (vinsn) && use_transform ())
- frag_now->tc_frag_data.is_specific_opcode = TRUE;
+ frag_now->tc_frag_data.is_specific_opcode = true;
if (finish_frag)
{
{
if (workaround_short_loop && use_transform ())
{
- maybe_has_short_loop = TRUE;
- frag_now->tc_frag_data.is_insn = TRUE;
+ maybe_has_short_loop = true;
+ frag_now->tc_frag_data.is_insn = true;
frag_var (rs_machine_dependent, 4, 4,
RELAX_ADD_NOP_IF_SHORT_LOOP,
frag_now->fr_symbol, frag_now->fr_offset, NULL);
- frag_now->tc_frag_data.is_insn = TRUE;
+ frag_now->tc_frag_data.is_insn = true;
frag_var (rs_machine_dependent, 4, 4,
RELAX_ADD_NOP_IF_SHORT_LOOP,
frag_now->fr_symbol, frag_now->fr_offset, NULL);
loop at least 12 bytes away from another loop's end. */
if (workaround_close_loop_end && use_transform ())
{
- maybe_has_close_loop_end = TRUE;
- frag_now->tc_frag_data.is_insn = TRUE;
+ maybe_has_close_loop_end = true;
+ frag_now->tc_frag_data.is_insn = true;
frag_var (rs_machine_dependent, 12, 12,
RELAX_ADD_NOP_IF_CLOSE_LOOP_END,
frag_now->fr_symbol, frag_now->fr_offset, NULL);
xtensa_set_frag_assembly_state (frag_now);
xtensa_maybe_create_trampoline_frag ();
/* Always create one here. */
- xtensa_maybe_create_literal_pool_frag (TRUE, FALSE);
+ xtensa_maybe_create_literal_pool_frag (true, false);
}
else if (is_branch && do_align_targets ())
{
&& xtensa_opcode_is_call (isa, vinsn->slots[0].opcode) == 1)
{
float freq = get_subseg_total_freq (now_seg, now_subseg);
- frag_now->tc_frag_data.is_insn = TRUE;
+ frag_now->tc_frag_data.is_insn = true;
frag_var (rs_machine_dependent, 4, (int) freq, RELAX_DESIRE_ALIGN,
frag_now->fr_symbol, frag_now->fr_offset, NULL);
xtensa_set_frag_assembly_state (frag_now);
}
\f
-/* xtensa_end and helper functions. */
+/* xtensa_md_finish and helper functions. */
static void xtensa_cleanup_align_frags (void);
static void xtensa_fix_target_frags (void);
static void xtensa_add_config_info (void);
void
-xtensa_end (void)
+xtensa_md_finish (void)
{
directive_balance ();
xtensa_flush_pending_output ();
- past_xtensa_end = TRUE;
+ past_xtensa_md_finish = true;
xtensa_move_literals ();
xtensa_check_frag_count ();
}
+struct trampoline_chain_entry
+{
+ symbolS *sym;
+ addressT offset;
+};
+
+/* Trampoline chain for a given (sym, offset) pair is a sorted array
+ of locations of trampoline jumps leading there. Jumps are represented
+ as pairs (sym, offset): trampoline frag symbol and offset of the jump
+ inside the frag. */
+struct trampoline_chain
+{
+ struct trampoline_chain_entry target;
+ struct trampoline_chain_entry *entry;
+ size_t n_entries;
+ size_t n_max;
+ bool needs_sorting;
+};
-struct trampoline_frag
+struct trampoline_chain_index
{
- struct trampoline_frag *next;
- bfd_boolean needs_jump_around;
- fragS *fragP;
- fixS *fixP;
+ struct trampoline_chain *entry;
+ size_t n_entries;
+ size_t n_max;
+ bool needs_sorting;
+};
+
+struct trampoline_index
+{
+ fragS **entry;
+ size_t n_entries;
+ size_t n_max;
};
struct trampoline_seg
{
struct trampoline_seg *next;
asection *seg;
- struct trampoline_frag trampoline_list;
+ /* Trampolines ordered by their frag fr_address */
+ struct trampoline_index index;
+ /* Known trampoline chains ordered by (sym, offset) pair */
+ struct trampoline_chain_index chain_index;
};
static struct trampoline_seg trampoline_seg_list;
#define J_RANGE (128 * 1024)
+#define J_MARGIN 4096
static int unreachable_count = 0;
if (++unreachable_count > 10)
{
- xtensa_create_trampoline_frag (FALSE);
+ xtensa_create_trampoline_frag (false);
clear_frag_count ();
unreachable_count = 0;
}
if (get_frag_count () > 8000)
{
- xtensa_create_trampoline_frag (TRUE);
+ xtensa_create_trampoline_frag (true);
clear_frag_count ();
unreachable_count = 0;
}
/* We create an area for a possible literal pool every N (default 5000)
frags or so. */
- xtensa_maybe_create_literal_pool_frag (TRUE, TRUE);
+ xtensa_maybe_create_literal_pool_frag (true, true);
}
static xtensa_insnbuf trampoline_buf = NULL;
#define TRAMPOLINE_FRAG_SIZE 3000
+static struct trampoline_seg *
+find_trampoline_seg (asection *seg)
+{
+ struct trampoline_seg *ts = trampoline_seg_list.next;
+ static struct trampoline_seg *mr;
+
+ if (mr && mr->seg == seg)
+ return mr;
+
+ for ( ; ts; ts = ts->next)
+ {
+ if (ts->seg == seg)
+ {
+ mr = ts;
+ return ts;
+ }
+ }
+
+ return NULL;
+}
+
+static size_t xg_find_trampoline (const struct trampoline_index *idx,
+ addressT addr)
+{
+ size_t a = 0;
+ size_t b = idx->n_entries;
+
+ while (b - a > 1)
+ {
+ size_t c = (a + b) / 2;
+
+ if (idx->entry[c]->fr_address <= addr)
+ a = c;
+ else
+ b = c;
+ }
+ return a;
+}
+
+static void xg_add_trampoline_to_index (struct trampoline_index *idx,
+ fragS *fragP)
+{
+ if (idx->n_entries == idx->n_max)
+ {
+ idx->n_max = (idx->n_entries + 1) * 2;
+ idx->entry = xrealloc (idx->entry,
+ sizeof (*idx->entry) * idx->n_max);
+ }
+ idx->entry[idx->n_entries] = fragP;
+ ++idx->n_entries;
+}
+
+static void xg_remove_trampoline_from_index (struct trampoline_index *idx,
+ size_t i)
+{
+ gas_assert (i < idx->n_entries);
+ memmove (idx->entry + i, idx->entry + i + 1,
+ (idx->n_entries - i - 1) * sizeof (*idx->entry));
+ --idx->n_entries;
+}
+
+static void xg_add_trampoline_to_seg (struct trampoline_seg *ts,
+ fragS *fragP)
+{
+ xg_add_trampoline_to_index (&ts->index, fragP);
+}
+
static void
-xtensa_create_trampoline_frag (bfd_boolean needs_jump_around)
+xtensa_create_trampoline_frag (bool needs_jump_around)
{
/* Emit a frag where we can place intermediate jump instructions,
in case we need to jump farther than 128K bytes.
We allocate enough for 1000 trampolines in each frag.
If that's not enough, oh well. */
- struct trampoline_seg *ts = trampoline_seg_list.next;
- struct trampoline_frag *tf;
+ struct trampoline_seg *ts = find_trampoline_seg (now_seg);
char *varP;
fragS *fragP;
int size = TRAMPOLINE_FRAG_SIZE;
- for ( ; ts; ts = ts->next)
- {
- if (ts->seg == now_seg)
- break;
- }
-
if (ts == NULL)
{
- ts = (struct trampoline_seg *)xcalloc(sizeof (struct trampoline_seg), 1);
+ ts = XCNEW(struct trampoline_seg);
ts->next = trampoline_seg_list.next;
trampoline_seg_list.next = ts;
ts->seg = now_seg;
trampoline_buf = xtensa_insnbuf_alloc (xtensa_default_isa);
trampoline_slotbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
}
- tf = XNEW (struct trampoline_frag);
- tf->next = ts->trampoline_list.next;
- ts->trampoline_list.next = tf;
- tf->needs_jump_around = needs_jump_around;
- tf->fragP = fragP;
- tf->fixP = NULL;
+ fragP->tc_frag_data.needs_jump_around = needs_jump_around;
+ xg_add_trampoline_to_seg (ts, fragP);
}
+static bool xg_is_trampoline_frag_full (const fragS *fragP)
+{
+ return fragP->fr_var < 3;
+}
-static struct trampoline_seg *
-find_trampoline_seg (asection *seg)
+static int xg_order_trampoline_chain_entry (const void *a, const void *b)
{
- struct trampoline_seg *ts = trampoline_seg_list.next;
+ const struct trampoline_chain_entry *pa = a;
+ const struct trampoline_chain_entry *pb = b;
- for ( ; ts; ts = ts->next)
+ if (pa->sym != pb->sym)
{
- if (ts->seg == seg)
- return ts;
+ valueT aval = S_GET_VALUE (pa->sym);
+ valueT bval = S_GET_VALUE (pb->sym);
+
+ if (aval != bval)
+ return aval < bval ? -1 : 1;
}
+ if (pa->offset != pb->offset)
+ return pa->offset < pb->offset ? -1 : 1;
+ return 0;
+}
- return NULL;
+static void xg_sort_trampoline_chain (struct trampoline_chain *tc)
+{
+ qsort (tc->entry, tc->n_entries, sizeof (*tc->entry),
+ xg_order_trampoline_chain_entry);
+ tc->needs_sorting = false;
+}
+
+/* Find entry index in the given chain with maximal address <= source. */
+static size_t xg_find_chain_entry (struct trampoline_chain *tc,
+ addressT source)
+{
+ size_t a = 0;
+ size_t b = tc->n_entries;
+
+ if (tc->needs_sorting)
+ xg_sort_trampoline_chain (tc);
+
+ while (b - a > 1)
+ {
+ size_t c = (a + b) / 2;
+ struct trampoline_chain_entry *e = tc->entry + c;
+
+ if (S_GET_VALUE(e->sym) + e->offset <= source)
+ a = c;
+ else
+ b = c;
+ }
+ return a;
+}
+
+/* Find the best jump target for the source in the given trampoline chain.
+ The best jump target is the one that results in the shortest path to the
+ final target, it's the location of the jump closest to the final target,
+ but within the J_RANGE - J_MARGIN from the source. */
+static struct trampoline_chain_entry *
+xg_get_best_chain_entry (struct trampoline_chain *tc, addressT source)
+{
+ addressT target = S_GET_VALUE(tc->target.sym) + tc->target.offset;
+ size_t i = xg_find_chain_entry (tc, source);
+ struct trampoline_chain_entry *e = tc->entry + i;
+ int step = target < source ? -1 : 1;
+ addressT chained_target;
+ offsetT off;
+
+ if (target > source &&
+ S_GET_VALUE(e->sym) + e->offset <= source &&
+ i + 1 < tc->n_entries)
+ ++i;
+
+ while (i + step < tc->n_entries)
+ {
+ struct trampoline_chain_entry *next = tc->entry + i + step;
+
+ chained_target = S_GET_VALUE(next->sym) + next->offset;
+ off = source - chained_target;
+
+ if (labs (off) >= J_RANGE - J_MARGIN)
+ break;
+
+ i += step;
+ }
+
+ e = tc->entry + i;
+ chained_target = S_GET_VALUE(e->sym) + e->offset;
+ off = source - chained_target;
+
+ if (labs (off) < J_MARGIN ||
+ labs (off) >= J_RANGE - J_MARGIN)
+ return &tc->target;
+ return tc->entry + i;
+}
+
+static int xg_order_trampoline_chain (const void *a, const void *b)
+{
+ const struct trampoline_chain *_pa = a;
+ const struct trampoline_chain *_pb = b;
+ const struct trampoline_chain_entry *pa = &_pa->target;
+ const struct trampoline_chain_entry *pb = &_pb->target;
+ symbolS *s1 = pa->sym;
+ symbolS *s2 = pb->sym;
+
+ if (s1 != s2)
+ {
+ symbolS *tmp = symbol_symbolS (s1);
+ if (tmp)
+ s1 = tmp;
+
+ tmp = symbol_symbolS (s2);
+ if (tmp)
+ s2 = tmp;
+
+ if (s1 != s2)
+ return s1 < s2 ? -1 : 1;
+ }
+
+ if (pa->offset != pb->offset)
+ return pa->offset < pb->offset ? -1 : 1;
+ return 0;
+}
+
+static struct trampoline_chain *
+xg_get_trampoline_chain (struct trampoline_seg *ts,
+ symbolS *sym,
+ addressT offset)
+{
+ struct trampoline_chain_index *idx = &ts->chain_index;
+ struct trampoline_chain c;
+
+ if (idx->n_entries == 0)
+ return NULL;
+
+ if (idx->needs_sorting)
+ {
+ qsort (idx->entry, idx->n_entries, sizeof (*idx->entry),
+ xg_order_trampoline_chain);
+ idx->needs_sorting = false;
+ }
+ c.target.sym = sym;
+ c.target.offset = offset;
+ return bsearch (&c, idx->entry, idx->n_entries,
+ sizeof (struct trampoline_chain),
+ xg_order_trampoline_chain);
+}
+
+/* Find trampoline chain in the given trampoline segment that is going
+ to the *sym + *offset. If found, replace *sym and *offset with the
+ best jump target in that chain. */
+static struct trampoline_chain *
+xg_find_best_eq_target (struct trampoline_seg *ts,
+ addressT source, symbolS **sym,
+ addressT *offset)
+{
+ struct trampoline_chain *tc = xg_get_trampoline_chain (ts, *sym, *offset);
+
+ if (tc)
+ {
+ struct trampoline_chain_entry *e = xg_get_best_chain_entry (tc, source);
+
+ *sym = e->sym;
+ *offset = e->offset;
+ }
+ return tc;
}
+static void xg_add_location_to_chain (struct trampoline_chain *tc,
+ symbolS *sym, addressT offset)
+{
+ struct trampoline_chain_entry *e;
+
+ if (tc->n_entries == tc->n_max)
+ {
+ tc->n_max = (tc->n_max + 1) * 2;
+ tc->entry = xrealloc (tc->entry, sizeof (*tc->entry) * tc->n_max);
+ }
+ e = tc->entry + tc->n_entries;
+ e->sym = sym;
+ e->offset = offset;
+ ++tc->n_entries;
+ tc->needs_sorting = true;
+}
+
+static struct trampoline_chain *
+xg_create_trampoline_chain (struct trampoline_seg *ts,
+ symbolS *sym, addressT offset)
+{
+ struct trampoline_chain_index *idx = &ts->chain_index;
+ struct trampoline_chain *tc;
+
+ if (idx->n_entries == idx->n_max)
+ {
+ idx->n_max = (idx->n_max + 1) * 2;
+ idx->entry = xrealloc (idx->entry,
+ sizeof (*idx->entry) * idx->n_max);
+ }
+
+ tc = idx->entry + idx->n_entries;
+ tc->target.sym = sym;
+ tc->target.offset = offset;
+ tc->entry = NULL;
+ tc->n_entries = 0;
+ tc->n_max = 0;
+ xg_add_location_to_chain (tc, sym, offset);
+
+ ++idx->n_entries;
+ idx->needs_sorting = true;
+
+ return tc;
+}
void dump_trampolines (void);
for ( ; ts; ts = ts->next)
{
+ size_t i;
asection *seg = ts->seg;
if (seg == NULL)
continue;
fprintf(stderr, "SECTION %s\n", seg->name);
- struct trampoline_frag *tf = ts->trampoline_list.next;
- for ( ; tf; tf = tf->next)
+
+ for (i = 0; i < ts->index.n_entries; ++i)
{
- if (tf->fragP == NULL)
- continue;
+ fragS *tf = ts->index.entry[i];
+
fprintf(stderr, " 0x%08x: fix=%d, jump_around=%s\n",
- (int)tf->fragP->fr_address, (int)tf->fragP->fr_fix,
- tf->needs_jump_around ? "T" : "F");
+ (int)tf->fr_address, (int)tf->fr_fix,
+ tf->tc_frag_data.needs_jump_around ? "T" : "F");
}
}
}
printf(" %ld <%d:%d> (%d) [%d]: ",
lpf->addr, lpf->priority, lpf->original_priority,
lpf->fragP->fr_line, count);
- //dump_frag(lpf->fragP);
+ /* dump_frag(lpf->fragP); */
}
}
}
static void
-xtensa_maybe_create_literal_pool_frag (bfd_boolean create,
- bfd_boolean only_if_needed)
+xtensa_maybe_create_literal_pool_frag (bool create, bool only_if_needed)
{
struct litpool_seg *lps = litpool_seg_list.next;
fragS *fragP;
struct litpool_frag *lpf;
- bfd_boolean needed = FALSE;
+ bool needed = false;
if (use_literal_section || !auto_litpools)
return;
if (lps == NULL)
{
- lps = (struct litpool_seg *)xcalloc (sizeof (struct litpool_seg), 1);
+ lps = XCNEW (struct litpool_seg);
lps->next = litpool_seg_list.next;
litpool_seg_list.next = lps;
lps->seg = now_seg;
lps->frag_list.next = &lps->frag_list;
lps->frag_list.prev = &lps->frag_list;
+ /* Put candidate literal pool at the beginning of every section,
+ so that even when section starts with literal load there's a
+ literal pool available. */
+ lps->frag_count = auto_litpool_limit;
}
lps->frag_count++;
{
if (only_if_needed)
{
- if (past_xtensa_end || !use_transform() ||
+ if (past_xtensa_md_finish || !use_transform() ||
frag_now->tc_frag_data.is_no_transform)
{
return;
}
else if (lps->frag_count > auto_litpool_limit)
{
- needed = TRUE;
+ needed = true;
}
else
{
}
else
{
- needed = TRUE;
+ needed = true;
}
}
lpf->fragP = fragP;
lpf->priority = (needed) ? (only_if_needed) ? 3 : 2 : 1;
lpf->original_priority = lpf->priority;
+ lpf->literal_count = 0;
lps->frag_count = 0;
}
frag_wane (fragP);
if (fragP->fr_type == rs_machine_dependent
&& fragP->fr_subtype == RELAX_UNREACHABLE)
- fragP->tc_frag_data.is_unreachable = TRUE;
+ fragP->tc_frag_data.is_unreachable = true;
}
}
}
}
-static bfd_boolean is_narrow_branch_guaranteed_in_range (fragS *, TInsn *);
+static bool is_narrow_branch_guaranteed_in_range (fragS *, TInsn *);
static void
xtensa_mark_narrow_branches (void)
static offsetT unrelaxed_frag_max_size (fragS *);
-static bfd_boolean
+static bool
is_narrow_branch_guaranteed_in_range (fragS *fragP, TInsn *tinsn)
{
const expressionS *exp = &tinsn->tok[1];
fragS *target_frag;
if (exp->X_op != O_symbol)
- return FALSE;
+ 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;
+ return false;
/* The branch doesn't branch over it's own frag,
but over the subsequent ones. */
fragP = fragP->fr_next;
}
if (max_distance <= MAX_IMMED6 && fragP == target_frag)
- return TRUE;
- return FALSE;
+ return true;
+ return false;
}
zero-cost loop instruction is the last in a section. */
if (targ_frag)
{
- targ_frag->tc_frag_data.is_first_loop_insn = TRUE;
+ targ_frag->tc_frag_data.is_first_loop_insn = true;
/* Do not widen a frag that is the first instruction of a
zero-cost loop. It makes that loop harder to align. */
if (targ_frag->fr_type == rs_machine_dependent
conditional branch or a retw/retw.n, convert this frag to one that
will generate a NOP. In any case close it off with a .fill 0. */
-static bfd_boolean next_instrs_are_b_retw (fragS *);
+static bool next_instrs_are_b_retw (fragS *);
static void
xtensa_fix_a0_b_retw_frags (void)
}
-static bfd_boolean
+static bool
next_instrs_are_b_retw (fragS *fragP)
{
xtensa_opcode opcode;
static xtensa_insnbuf insnbuf = NULL;
static xtensa_insnbuf slotbuf = NULL;
xtensa_isa isa = xtensa_default_isa;
- int offset = 0;
+ unsigned int offset = 0;
int slot;
- bfd_boolean branch_seen = FALSE;
+ bool branch_seen = false;
if (!insnbuf)
{
}
if (next_fragP == NULL)
- return FALSE;
+ return false;
/* Check for the conditional branch. */
xtensa_insnbuf_from_chars
(isa, insnbuf, (unsigned char *) &next_fragP->fr_literal[offset], 0);
fmt = xtensa_format_decode (isa, insnbuf);
if (fmt == XTENSA_UNDEFINED)
- return FALSE;
+ return false;
for (slot = 0; slot < xtensa_format_num_slots (isa, fmt); slot++)
{
}
if (!branch_seen)
- return FALSE;
+ return false;
offset += xtensa_format_length (isa, fmt);
if (offset == next_fragP->fr_fix)
}
if (next_fragP == NULL)
- return FALSE;
+ return false;
/* Check for the retw/retw.n. */
xtensa_insnbuf_from_chars
have no problems. */
if (fmt == XTENSA_UNDEFINED
|| xtensa_format_num_slots (isa, fmt) != 1)
- return FALSE;
+ return false;
xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf);
opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf);
if (opcode == xtensa_retw_opcode || opcode == xtensa_retw_n_opcode)
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
loop end label, convert this frag to one that will generate a NOP.
In any case close it off with a .fill 0. */
-static bfd_boolean next_instr_is_loop_end (fragS *);
+static bool next_instr_is_loop_end (fragS *);
static void
xtensa_fix_b_j_loop_end_frags (void)
}
-static bfd_boolean
+static bool
next_instr_is_loop_end (fragS *fragP)
{
const fragS *next_fragP;
if (next_frag_is_loop_target (fragP))
- return FALSE;
+ return false;
next_fragP = next_non_empty_frag (fragP);
if (next_fragP == NULL)
- return FALSE;
+ return false;
if (!next_frag_is_loop_target (next_fragP))
- return FALSE;
+ return false;
/* If the size is >= 3 then there is more than one instruction here.
The hardware bug will not fire. */
if (next_fragP->fr_fix > 3)
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
case rs_leb128:
case rs_cfa:
case rs_dwarf2dbg:
+ case rs_sframe:
/* No further adjustments needed. */
break;
case rs_machine_dependent:
then convert this frag (and maybe the next one) to generate a NOP.
In any case close it off with a .fill 0. */
-static int count_insns_to_loop_end (fragS *, bfd_boolean, int);
-static bfd_boolean branch_before_loop_end (fragS *);
+static int count_insns_to_loop_end (fragS *, bool, int);
+static bool branch_before_loop_end (fragS *);
static void
xtensa_fix_short_loop_frags (void)
if (fragP->fr_type == rs_machine_dependent
&& fragP->fr_subtype == RELAX_ADD_NOP_IF_SHORT_LOOP)
{
- if (count_insns_to_loop_end (fragP->fr_next, TRUE, 3) < 3
+ if (count_insns_to_loop_end (fragP->fr_next, true, 3) < 3
&& (branch_before_loop_end (fragP->fr_next)
|| (workaround_all_short_loops
&& current_opcode != XTENSA_UNDEFINED
static int
count_insns_to_loop_end (fragS *base_fragP,
- bfd_boolean count_relax_add,
+ bool count_relax_add,
int max_count)
{
fragS *fragP = NULL;
xtensa_isa isa = xtensa_default_isa;
static xtensa_insnbuf insnbuf = NULL;
int insn_count = 0;
- int offset = 0;
+ unsigned int offset = 0;
if (!fragP->tc_frag_data.is_insn)
return insn_count;
}
-static bfd_boolean unrelaxed_frag_has_b_j (fragS *);
+static bool unrelaxed_frag_has_b_j (fragS *);
-static bfd_boolean
+static bool
branch_before_loop_end (fragS *base_fragP)
{
fragS *fragP;
fragP = fragP->fr_next)
{
if (unrelaxed_frag_has_b_j (fragP))
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
-static bfd_boolean
+static bool
unrelaxed_frag_has_b_j (fragS *fragP)
{
static xtensa_insnbuf insnbuf = NULL;
xtensa_isa isa = xtensa_default_isa;
- int offset = 0;
+ unsigned int offset = 0;
if (!fragP->tc_frag_data.is_insn)
- return FALSE;
+ return false;
if (!insnbuf)
insnbuf = xtensa_insnbuf_alloc (isa);
(isa, insnbuf, (unsigned char *) fragP->fr_literal + offset, 0);
fmt = xtensa_format_decode (isa, insnbuf);
if (fmt == XTENSA_UNDEFINED)
- return FALSE;
+ return false;
for (slot = 0; slot < xtensa_format_num_slots (isa, fmt); slot++)
{
get_opcode_from_buf (fragP->fr_literal + offset, slot);
if (xtensa_opcode_is_branch (isa, opcode) == 1
|| xtensa_opcode_is_jump (isa, opcode) == 1)
- return TRUE;
+ return true;
}
offset += xtensa_format_length (isa, fmt);
}
- return FALSE;
+ return false;
}
/* Checks to be made after initial assembly but before relaxation. */
-static bfd_boolean is_empty_loop (const TInsn *, fragS *);
-static bfd_boolean is_local_forward_loop (const TInsn *, fragS *);
+static bool is_empty_loop (const TInsn *, fragS *);
+static bool is_local_forward_loop (const TInsn *, fragS *);
static void
xtensa_sanity_check (void)
/* Return TRUE if the loop target is the next non-zero fragment. */
-static bfd_boolean
+static bool
is_empty_loop (const TInsn *insn, fragS *fragP)
{
const expressionS *exp;
fragS *next_fragP;
if (insn->insn_type != ITYPE_INSN)
- return FALSE;
+ return false;
if (xtensa_opcode_is_loop (xtensa_default_isa, insn->opcode) != 1)
- return FALSE;
+ return false;
if (insn->ntok <= LOOP_IMMED_OPN)
- return FALSE;
+ return false;
exp = &insn->tok[LOOP_IMMED_OPN];
if (exp->X_op != O_symbol)
- return FALSE;
+ return false;
symbolP = exp->X_add_symbol;
if (!symbolP)
- return FALSE;
+ return false;
if (symbol_get_frag (symbolP) == NULL)
- return FALSE;
+ return false;
if (S_GET_VALUE (symbolP) != 0)
- return FALSE;
+ return false;
/* Walk through the zero-size fragments from this one. If we find
the target fragment, then this is a zero-size loop. */
next_fragP = next_fragP->fr_next)
{
if (next_fragP == symbol_get_frag (symbolP))
- return TRUE;
+ return true;
if (next_fragP->fr_fix != 0)
- return FALSE;
+ return false;
}
- return FALSE;
+ return false;
}
-static bfd_boolean
+static bool
is_local_forward_loop (const TInsn *insn, fragS *fragP)
{
const expressionS *exp;
fragS *next_fragP;
if (insn->insn_type != ITYPE_INSN)
- return FALSE;
+ return false;
if (xtensa_opcode_is_loop (xtensa_default_isa, insn->opcode) != 1)
- return FALSE;
+ return false;
if (insn->ntok <= LOOP_IMMED_OPN)
- return FALSE;
+ return false;
exp = &insn->tok[LOOP_IMMED_OPN];
if (exp->X_op != O_symbol)
- return FALSE;
+ return false;
symbolP = exp->X_add_symbol;
if (!symbolP)
- return FALSE;
+ return false;
if (symbol_get_frag (symbolP) == NULL)
- return FALSE;
+ return false;
/* Walk through fragments until we find the target.
If we do not find the target, then this is an invalid loop. */
next_fragP = next_fragP->fr_next)
{
if (next_fragP == symbol_get_frag (symbolP))
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
-
#define XTINFO_NAME "Xtensa_Info"
#define XTINFO_NAMESZ 12
#define XTINFO_TYPE 1
int sz;
info_sec = subseg_new (".xtensa.info", 0);
- bfd_set_section_flags (stdoutput, info_sec, SEC_HAS_CONTENTS | SEC_READONLY);
+ bfd_set_section_flags (info_sec, SEC_HAS_CONTENTS | SEC_READONLY);
data = XNEWVEC (char, 100);
sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n",
- XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI);
+ XSHAL_USE_ABSOLUTE_LITERALS, xtensa_abi_choice ());
sz = strlen (data) + 1;
/* Add enough null terminators to pad to a word boundary. */
static int
get_text_align_max_fill_size (int align_pow,
- bfd_boolean use_nops,
- bfd_boolean use_no_density)
+ bool use_nops,
+ bool use_no_density)
{
if (!use_nops)
return (1 << align_pow);
get_text_align_fill_size (addressT address,
int align_pow,
int target_size,
- bfd_boolean use_nops,
- bfd_boolean use_no_density)
+ bool use_nops,
+ bool use_no_density)
{
addressT alignment, fill, fill_limit, fill_step;
- bfd_boolean skip_one = FALSE;
+ bool skip_one = false;
alignment = (1 << align_pow);
gas_assert (target_size > 0 && alignment >= (addressT) target_size);
/* Combine 2- and 3-byte NOPs to fill anything larger than one. */
fill_limit = alignment * 2;
fill_step = 1;
- skip_one = TRUE;
+ skip_one = true;
}
else
{
/* This will assert if it is not possible. */
static int
-get_text_align_nop_count (offsetT fill_size, bfd_boolean use_no_density)
+get_text_align_nop_count (offsetT fill_size, bool use_no_density)
{
int count = 0;
static int
get_text_align_nth_nop_size (offsetT fill_size,
int n,
- bfd_boolean use_no_density)
+ bool use_no_density)
{
int count = 0;
int align_power;
fragS *first_insn;
xtensa_opcode opcode;
- bfd_boolean is_loop;
+ bool is_loop;
gas_assert (fragP->fr_type == rs_machine_dependent);
gas_assert (fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE);
record_alignment (now_seg, align_power);
fill_size = get_text_align_fill_size
- (address + pre_opcode_bytes, align_power, first_insn_size, TRUE,
+ (address + pre_opcode_bytes, align_power, first_insn_size, true,
fragP->tc_frag_data.is_no_density);
return address + fill_size;
addressT target_address, loop_insn_offset;
int target_size;
xtensa_opcode loop_opcode;
- bfd_boolean is_loop;
+ bool is_loop;
int align_power;
offsetT opt_diff;
offsetT branch_align;
if (target_size > branch_align)
target_size = branch_align;
opt_diff = get_text_align_fill_size (address, align_power,
- target_size, FALSE, FALSE);
+ target_size, false, false);
*max_diff = (opt_diff + branch_align
- (target_size + ((address + opt_diff) % branch_align)));
address + loop_insn_offset + xg_get_single_size (loop_opcode);
align_power = get_text_align_power (target_size);
opt_diff = get_text_align_fill_size (target_address, align_power,
- target_size, FALSE, FALSE);
+ target_size, false, false);
*max_diff = xtensa_fetch_width
- ((target_address + opt_diff) % xtensa_fetch_width)
static long relax_frag_loop_align (fragS *, long);
static long relax_frag_for_align (fragS *, long);
static long relax_frag_immed
- (segT, fragS *, long, int, xtensa_format, int, int *, bfd_boolean);
-
-typedef struct cached_fixup cached_fixupS;
-struct cached_fixup
-{
- int addr;
- int target;
- int delta;
- fixS *fixP;
-};
+ (segT, fragS *, long, int, xtensa_format, int, int *, bool);
-typedef struct fixup_cache fixup_cacheS;
-struct fixup_cache
+/* Get projected address for the first fulcrum on a path from source to
+ target. */
+static addressT xg_get_fulcrum (addressT source, addressT target)
{
- cached_fixupS *fixups;
- unsigned n_fixups;
- unsigned n_max;
+ offsetT delta = target - source;
+ int n;
- segT seg;
- fragS *first_frag;
-};
+ n = (labs (delta) + J_RANGE - J_MARGIN - 1) / (J_RANGE - J_MARGIN);
+ return source + delta / n;
+}
-static int fixup_order (const void *a, const void *b)
+/* Given trampoline index, source and target of a jump find the best
+ candidate trampoline for the first fulcrum. The best trampoline is
+ the one in the reach of "j' instruction from the source, closest to
+ the projected fulcrum address, and preferrably w/o a jump around or
+ with already initialized jump around. */
+static size_t xg_find_best_trampoline (struct trampoline_index *idx,
+ addressT source, addressT target)
{
- const cached_fixupS *pa = a;
- const cached_fixupS *pb = b;
+ addressT fulcrum = xg_get_fulcrum (source, target);
+ size_t dist = 0;
+ size_t best = -1;
+ size_t base_tr = xg_find_trampoline (idx, fulcrum);
+ int checked = 1;
- if (pa->addr == pb->addr)
+ /* Check trampoline frags around the base_tr to find the best. */
+ for (dist = 0; checked; ++dist)
{
- if (pa->target == pb->target)
- {
- if (pa->fixP->fx_r_type == pb->fixP->fx_r_type)
- return 0;
- return pa->fixP->fx_r_type < pb->fixP->fx_r_type ? -1 : 1;
- }
- return pa->target - pb->target;
+ int i;
+ size_t tr = base_tr - dist;
+
+ checked = 0;
+
+ /* Trampolines are checked in the following order:
+ base_tr, base_tr + 1, base_tr - 1, base_tr + 2, base_tr - 2 */
+ for (i = 0; i < 2; ++i, tr = base_tr + dist + 1)
+ if (tr < idx->n_entries)
+ {
+ fragS *trampoline_frag = idx->entry[tr];
+ offsetT off;
+
+ /* Don't check trampolines outside source - target interval. */
+ if ((trampoline_frag->fr_address < source &&
+ trampoline_frag->fr_address < target) ||
+ (trampoline_frag->fr_address > source &&
+ trampoline_frag->fr_address > target))
+ continue;
+
+ /* Don't choose trampoline that contains the source. */
+ if (source >= trampoline_frag->fr_address
+ && source <= trampoline_frag->fr_address +
+ trampoline_frag->fr_fix)
+ continue;
+
+ off = trampoline_frag->fr_address - fulcrum;
+ /* Stop if some trampoline is found and the search is more than
+ J_RANGE / 4 from the projected fulcrum. A trampoline w/o jump
+ around is nice, but it shouldn't have much overhead. */
+ if (best < idx->n_entries && labs (off) > J_RANGE / 4)
+ return best;
+
+ off = trampoline_frag->fr_address - source;
+ if (labs (off) < J_RANGE - J_MARGIN)
+ {
+ ++checked;
+ /* Stop if a trampoline w/o jump around is found or initialized
+ trampoline with jump around is found. */
+ if (!trampoline_frag->tc_frag_data.needs_jump_around ||
+ trampoline_frag->fr_fix)
+ return tr;
+ else if (best >= idx->n_entries)
+ best = tr;
+ }
+ }
}
- return pa->addr - pb->addr;
+
+ if (best < idx->n_entries)
+ return best;
+ else
+ as_fatal (_("cannot find suitable trampoline"));
+}
+
+static fixS *xg_relax_fixup (struct trampoline_index *idx, fixS *fixP)
+{
+ symbolS *s = fixP->fx_addsy;
+ addressT source = fixP->fx_frag->fr_address;
+ addressT target = S_GET_VALUE (s) + fixP->fx_offset;
+ size_t tr = xg_find_best_trampoline (idx, source, target);
+ fragS *trampoline_frag = idx->entry[tr];
+ fixS *newfixP;
+
+ init_trampoline_frag (trampoline_frag);
+ newfixP = xg_append_jump (trampoline_frag,
+ fixP->fx_addsy, fixP->fx_offset);
+
+ /* Adjust the fixup for the original "j" instruction to
+ point to the newly added jump. */
+ fixP->fx_addsy = trampoline_frag->fr_symbol;
+ fixP->fx_offset = trampoline_frag->fr_fix - 3;
+ fixP->tc_fix_data.X_add_symbol = trampoline_frag->fr_symbol;
+ fixP->tc_fix_data.X_add_number = trampoline_frag->fr_fix - 3;
+
+ trampoline_frag->tc_frag_data.relax_seen = false;
+
+ if (xg_is_trampoline_frag_full (trampoline_frag))
+ xg_remove_trampoline_from_index (idx, tr);
+
+ return newfixP;
}
-static bfd_boolean xtensa_make_cached_fixup (cached_fixupS *o, fixS *fixP)
+static bool xg_is_relaxable_fixup (fixS *fixP)
{
xtensa_isa isa = xtensa_default_isa;
- int addr = fixP->fx_frag->fr_address;
- int target;
- int delta;
+ addressT addr = fixP->fx_frag->fr_address;
+ addressT target;
+ offsetT delta;
symbolS *s = fixP->fx_addsy;
int slot;
xtensa_format fmt;
if (fixP->fx_r_type < BFD_RELOC_XTENSA_SLOT0_OP ||
fixP->fx_r_type > BFD_RELOC_XTENSA_SLOT14_OP)
- return FALSE;
- target = S_GET_VALUE (s);
+ return false;
+
+ target = S_GET_VALUE (s) + fixP->fx_offset;
delta = target - addr;
- if (abs(delta) < J_RANGE / 2)
- return FALSE;
+ if (labs (delta) < J_RANGE - J_MARGIN)
+ return false;
xtensa_insnbuf_from_chars (isa, trampoline_buf,
(unsigned char *) fixP->fx_frag->fr_literal +
slot = fixP->tc_fix_data.slot;
xtensa_format_get_slot (isa, fmt, slot, trampoline_buf, trampoline_slotbuf);
opcode = xtensa_opcode_decode (isa, fmt, slot, trampoline_slotbuf);
- if (opcode != xtensa_j_opcode)
- return FALSE;
-
- o->addr = addr;
- o->target = target;
- o->delta = delta;
- o->fixP = fixP;
-
- return TRUE;
+ return opcode == xtensa_j_opcode;
}
-static void xtensa_realloc_fixup_cache (fixup_cacheS *cache, unsigned add)
+static void xg_relax_fixups (struct trampoline_seg *ts)
{
- if (cache->n_fixups + add > cache->n_max)
- {
- cache->n_max = (cache->n_fixups + add) * 2;
- cache->fixups = XRESIZEVEC (cached_fixupS, cache->fixups, cache->n_max);
- }
-}
+ struct trampoline_index *idx = &ts->index;
+ segment_info_type *seginfo = seg_info (now_seg);
+ fixS *fx;
-static void xtensa_cache_relaxable_fixups (fixup_cacheS *cache,
- segment_info_type *seginfo)
-{
- fixS *fixP;
-
- cache->n_fixups = 0;
-
- for (fixP = seginfo->fix_root; fixP ; fixP = fixP->fx_next)
+ for (fx = seginfo->fix_root; fx; fx = fx->fx_next)
{
- xtensa_realloc_fixup_cache (cache, 1);
-
- if (xtensa_make_cached_fixup (cache->fixups + cache->n_fixups, fixP))
- ++cache->n_fixups;
- }
- qsort (cache->fixups, cache->n_fixups, sizeof (*cache->fixups), fixup_order);
-}
-
-static unsigned xtensa_find_first_cached_fixup (const fixup_cacheS *cache,
- int addr)
-{
- unsigned a = 0;
- unsigned b = cache->n_fixups;
+ fixS *fixP = fx;
+ struct trampoline_chain *tc = NULL;
- while (b - a > 1)
- {
- unsigned c = (a + b) / 2;
+ if (xg_is_relaxable_fixup (fixP))
+ {
+ tc = xg_find_best_eq_target (ts, fixP->fx_frag->fr_address,
+ &fixP->fx_addsy, &fixP->fx_offset);
+ if (!tc)
+ tc = xg_create_trampoline_chain (ts, fixP->fx_addsy,
+ fixP->fx_offset);
+ gas_assert (tc);
+ }
- if (cache->fixups[c].addr < addr)
- a = c;
- else
- b = c;
+ while (xg_is_relaxable_fixup (fixP))
+ {
+ fixP = xg_relax_fixup (idx, fixP);
+ xg_add_location_to_chain (tc, fixP->fx_frag->fr_symbol,
+ fixP->fx_where);
+ }
}
- return a;
-}
-
-static void xtensa_delete_cached_fixup (fixup_cacheS *cache, unsigned i)
-{
- memmove (cache->fixups + i, cache->fixups + i + 1,
- (cache->n_fixups - i - 1) * sizeof (*cache->fixups));
- --cache->n_fixups;
}
-static bfd_boolean xtensa_add_cached_fixup (fixup_cacheS *cache, fixS *fixP)
+/* Given a trampoline frag relax all jumps that might want to use this
+ trampoline. Only do real work once per relaxation cycle, when
+ xg_relax_trampoline is called for the first trampoline in the now_seg.
+ Don't use stretch, don't update new_stretch: place fulcrums with a
+ slack to tolerate code movement. In the worst case if a jump between
+ two trampolines wouldn't reach the next relaxation pass will fix it. */
+static void xg_relax_trampoline (fragS *fragP, long stretch ATTRIBUTE_UNUSED,
+ long *new_stretch ATTRIBUTE_UNUSED)
{
- cached_fixupS o;
- unsigned i;
+ struct trampoline_seg *ts = find_trampoline_seg (now_seg);
- if (!xtensa_make_cached_fixup (&o, fixP))
- return FALSE;
- xtensa_realloc_fixup_cache (cache, 1);
- i = xtensa_find_first_cached_fixup (cache, o.addr);
- if (i < cache->n_fixups)
- {
- ++i;
- memmove (cache->fixups + i + 1, cache->fixups + i,
- (cache->n_fixups - i) * sizeof (*cache->fixups));
- }
- cache->fixups[i] = o;
- ++cache->n_fixups;
- return TRUE;
+ if (ts->index.n_entries && ts->index.entry[0] == fragP)
+ xg_relax_fixups (ts);
}
/* Return the number of bytes added to this fragment, given that the
new_stretch += relax_frag_immed
(now_seg, fragP, stretch,
fragP->tc_frag_data.slot_subtypes[slot] - RELAX_IMMED,
- fmt, slot, stretched_p, FALSE);
+ fmt, slot, stretched_p, false);
break;
default:
litpool_slotbuf = xtensa_insnbuf_alloc (isa);
}
new_stretch += 3;
- fragP->tc_frag_data.relax_seen = FALSE; /* Need another pass. */
- fragP->tc_frag_data.is_insn = TRUE;
+ fragP->tc_frag_data.relax_seen = false; /* Need another pass. */
+ fragP->tc_frag_data.is_insn = true;
tinsn_init (&insn);
insn.insn_type = ITYPE_INSN;
insn.opcode = xtensa_j_opcode;
fragP->fr_fix += 3;
fragP->fr_var -= 3;
/* Add a fix-up. */
- fix_new (fragP, 0, 3, fragP->fr_symbol, 0, TRUE,
+ fix_new (fragP, 0, 3, fragP->fr_symbol, 0, true,
BFD_RELOC_XTENSA_SLOT0_OP);
}
break;
case RELAX_TRAMPOLINE:
if (fragP->tc_frag_data.relax_seen)
- {
- static fixup_cacheS fixup_cache;
- segment_info_type *seginfo = seg_info (now_seg);
- int trampaddr = fragP->fr_address + fragP->fr_fix;
- int searchaddr = trampaddr < J_RANGE ? 0 : trampaddr - J_RANGE;
- unsigned i;
-
- if (now_seg != fixup_cache.seg ||
- fragP == fixup_cache.first_frag ||
- fixup_cache.first_frag == NULL)
- {
- xtensa_cache_relaxable_fixups (&fixup_cache, seginfo);
- fixup_cache.seg = now_seg;
- fixup_cache.first_frag = fragP;
- }
-
- /* Scan for jumps that will not reach. */
- for (i = xtensa_find_first_cached_fixup (&fixup_cache, searchaddr);
- i < fixup_cache.n_fixups; ++i)
-
- {
- fixS *fixP = fixup_cache.fixups[i].fixP;
- int target = fixup_cache.fixups[i].target;
- int addr = fixup_cache.fixups[i].addr;
- int delta = fixup_cache.fixups[i].delta + stretch;
-
- trampaddr = fragP->fr_address + fragP->fr_fix;
-
- if (addr + J_RANGE < trampaddr)
- continue;
- if (addr > trampaddr + J_RANGE)
- break;
- if (abs (delta) < J_RANGE)
- continue;
-
- slot = fixP->tc_fix_data.slot;
-
- if (delta > J_RANGE || delta < -1 * J_RANGE)
- { /* Found an out-of-range jump; scan the list of trampolines for the best match. */
- struct trampoline_seg *ts = find_trampoline_seg (now_seg);
- struct trampoline_frag *tf = ts->trampoline_list.next;
- struct trampoline_frag *prev = &ts->trampoline_list;
- int lower = (target < addr) ? target : addr;
- int upper = (target > addr) ? target : addr;
- int midpoint = lower + (upper - lower) / 2;
-
- if ((upper - lower) > 2 * J_RANGE)
- {
- /* One trampoline won't suffice; we need multiple jumps.
- Jump to the trampoline that's farthest, but still in
- range relative to the original "j" instruction. */
- for ( ; tf; prev = tf, tf = tf->next )
- {
- int this_addr = tf->fragP->fr_address + tf->fragP->fr_fix;
- int next_addr = (tf->next) ? tf->next->fragP->fr_address + tf->next->fragP->fr_fix : 0 ;
-
- if (addr == lower)
- {
- /* Forward jump. */
- if (this_addr - addr < J_RANGE)
- break;
- }
- else
- {
- /* Backward jump. */
- if (next_addr == 0 || addr - next_addr > J_RANGE)
- break;
- }
- }
- }
- else
- {
- struct trampoline_frag *best_tf = NULL;
- int best_delta = 0;
-
- for ( ; tf; prev = tf, tf = tf->next )
- {
- int this_addr = tf->fragP->fr_address + tf->fragP->fr_fix;
- int this_delta = abs (this_addr - midpoint);
-
- if (!best_tf || this_delta < best_delta)
- {
- best_tf = tf;
- best_delta = this_delta;
- }
- }
- tf = best_tf;
- }
- if (tf->fragP == fragP)
- {
- if (abs (addr - trampaddr) < J_RANGE)
- { /* The trampoline is in range of original; fix it! */
- fixS *newfixP;
- int offset;
- TInsn insn;
- symbolS *lsym;
- fragS *fP; /* The out-of-range jump. */
-
- new_stretch += init_trampoline_frag (tf);
- offset = fragP->fr_fix; /* Where to assemble the j insn. */
- lsym = fragP->fr_symbol;
- fP = fixP->fx_frag;
- /* Assemble a jump to the target label here. */
- tinsn_init (&insn);
- insn.insn_type = ITYPE_INSN;
- insn.opcode = xtensa_j_opcode;
- insn.ntok = 1;
- set_expr_symbol_offset (&insn.tok[0], lsym, offset);
- fmt = xg_get_single_format (xtensa_j_opcode);
- tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf);
- xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf);
- xtensa_insnbuf_to_chars (isa, trampoline_buf, (unsigned char *)fragP->fr_literal + offset, 3);
- fragP->fr_fix += 3;
- fragP->fr_var -= 3;
- /* Add a fix-up for the original j insn. */
- newfixP = fix_new (fP, fixP->fx_where, fixP->fx_size, lsym, fragP->fr_fix - 3, TRUE, fixP->fx_r_type);
- newfixP->fx_no_overflow = 1;
- newfixP->tc_fix_data.X_add_symbol = lsym;
- newfixP->tc_fix_data.X_add_number = offset;
- newfixP->tc_fix_data.slot = slot;
-
- xtensa_delete_cached_fixup (&fixup_cache, i);
- xtensa_add_cached_fixup (&fixup_cache, newfixP);
-
- /* Move the fix-up from the original j insn to this one. */
- fixP->fx_frag = fragP;
- fixP->fx_where = fragP->fr_fix - 3;
- fixP->tc_fix_data.slot = 0;
-
- xtensa_add_cached_fixup (&fixup_cache, fixP);
-
- /* re-do current fixup */
- --i;
-
- /* Adjust the jump around this trampoline (if present). */
- if (tf->fixP != NULL)
- {
- tf->fixP->fx_offset += 3;
- }
- new_stretch += 3;
- fragP->tc_frag_data.relax_seen = FALSE; /* Need another pass. */
- /* Do we have room for more? */
- if (fragP->fr_var < 3)
- { /* No, convert to fill. */
- frag_wane (fragP);
- fragP->fr_subtype = 0;
- /* Remove from the trampoline_list. */
- prev->next = tf->next;
- if (fragP == fixup_cache.first_frag)
- fixup_cache.first_frag = NULL;
- break;
- }
- }
- }
- }
- }
- }
+ xg_relax_trampoline (fragP, stretch, &new_stretch);
break;
default:
/* Tell gas we need another relaxation pass. */
if (! fragP->tc_frag_data.relax_seen)
{
- fragP->tc_frag_data.relax_seen = TRUE;
+ fragP->tc_frag_data.relax_seen = true;
*stretched_p = 1;
}
char *nop_buf = fragP->fr_literal + fragP->fr_fix;
int length = fragP->tc_frag_data.is_no_density ? 3 : 2;
assemble_nop (length, nop_buf);
- fragP->tc_frag_data.is_insn = TRUE;
+ fragP->tc_frag_data.is_insn = true;
if (fragP->fr_var < length)
{
int *wide_nops,
int *narrow_nops,
int *widens,
- bfd_boolean *paddable)
+ bool *paddable)
{
fragS *fragP = *fragPP;
addressT address = fragP->fr_address;
switch (fragP->fr_subtype)
{
case RELAX_UNREACHABLE:
- *paddable = TRUE;
+ *paddable = true;
break;
case RELAX_FILL_NOP:
int num_widens = 0;
int wide_nops = 0;
int narrow_nops = 0;
- bfd_boolean paddable = FALSE;
+ bool paddable = false;
offsetT local_opt_diff;
offsetT opt_diff;
offsetT max_diff;
int glob_widens = 0;
int dnn = 0;
int dw = 0;
- bfd_boolean glob_pad = 0;
+ bool glob_pad = 0;
address = find_address_of_next_align_frag
(&fragP, &glob_widens, &dnn, &dw, &glob_pad);
/* If there is a padable portion, then skip. */
}
-static struct trampoline_frag *
-search_trampolines (TInsn *tinsn, fragS *fragP, bfd_boolean unreachable_only)
+static fragS *
+xg_find_best_trampoline_for_tinsn (TInsn *tinsn, fragS *fragP)
{
- struct trampoline_seg *ts = find_trampoline_seg (now_seg);
- struct trampoline_frag *tf = (ts) ? ts->trampoline_list.next : NULL;
- struct trampoline_frag *best_tf = NULL;
- int best_delta = 0;
- int best_addr = 0;
symbolS *sym = tinsn->tok[0].X_add_symbol;
- offsetT target = S_GET_VALUE (sym) + tinsn->tok[0].X_add_number;
- offsetT addr = fragP->fr_address;
- offsetT lower = (addr < target) ? addr : target;
- offsetT upper = (addr > target) ? addr : target;
- int delta = upper - lower;
- offsetT midpoint = lower + delta / 2;
- int this_delta = -1;
- int this_addr = -1;
-
- if (delta > 2 * J_RANGE)
- {
- /* One trampoline won't do; we need multiple.
- Choose the farthest trampoline that's still in range of the original
- and let a later pass finish the job. */
- for ( ; tf; tf = tf->next)
- {
- int next_addr = (tf->next) ? tf->next->fragP->fr_address + tf->next->fragP->fr_fix : 0;
-
- this_addr = tf->fragP->fr_address + tf->fragP->fr_fix;
- if (lower == addr)
- {
- /* Forward jump. */
- if (this_addr - addr < J_RANGE)
- break;
- }
- else
- {
- /* Backward jump. */
- if (next_addr == 0 || addr - next_addr > J_RANGE)
- break;
- }
- }
- if (abs (addr - this_addr) < J_RANGE)
- return tf;
+ addressT source = fragP->fr_address;
+ addressT target = S_GET_VALUE (sym) + tinsn->tok[0].X_add_number;
+ struct trampoline_seg *ts = find_trampoline_seg (now_seg);
+ size_t i;
- return NULL;
- }
- for ( ; tf; tf = tf->next)
- {
- this_addr = tf->fragP->fr_address + tf->fragP->fr_fix;
- this_delta = abs (this_addr - midpoint);
- if (unreachable_only && tf->needs_jump_around)
- continue;
- if (!best_tf || this_delta < best_delta)
- {
- best_tf = tf;
- best_delta = this_delta;
- best_addr = this_addr;
- }
- }
+ if (!ts || !ts->index.n_entries)
+ return NULL;
- if (best_tf &&
- best_delta < J_RANGE &&
- abs(best_addr - lower) < J_RANGE &&
- abs(best_addr - upper) < J_RANGE)
- return best_tf;
+ i = xg_find_best_trampoline (&ts->index, source, target);
- return NULL; /* No suitable trampoline found. */
+ return ts->index.entry[i];
}
-static struct trampoline_frag *
-get_best_trampoline (TInsn *tinsn, fragS *fragP)
+/* Append jump to sym + offset to the end of the trampoline frag fragP.
+ Adjust fragP's jump around if it's present. Adjust fragP's fr_fix/fr_var
+ and finish the frag if it's full (but don't remove it from the trampoline
+ frag index). Return fixup for the newly created jump. */
+static fixS *xg_append_jump (fragS *fragP, symbolS *sym, offsetT offset)
{
- struct trampoline_frag *tf = NULL;
-
- tf = search_trampolines (tinsn, fragP, TRUE); /* Try unreachable first. */
-
- if (tf == NULL)
- tf = search_trampolines (tinsn, fragP, FALSE); /* Try ones needing a jump-around, too. */
+ fixS *fixP;
+ TInsn insn;
+ xtensa_format fmt;
+ xtensa_isa isa = xtensa_default_isa;
- return tf;
-}
+ gas_assert (fragP->fr_var >= 3);
+ tinsn_init (&insn);
+ insn.insn_type = ITYPE_INSN;
+ insn.opcode = xtensa_j_opcode;
+ insn.ntok = 1;
+ set_expr_symbol_offset (&insn.tok[0], sym, offset);
+ fmt = xg_get_single_format (xtensa_j_opcode);
+ tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf);
+ xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf);
+ xtensa_insnbuf_to_chars (isa, trampoline_buf,
+ (unsigned char *)fragP->fr_literal + fragP->fr_fix, 3);
+ fixP = fix_new (fragP, fragP->fr_fix, 3, sym, offset, true,
+ BFD_RELOC_XTENSA_SLOT0_OP);
+ fixP->tc_fix_data.slot = 0;
+ fragP->fr_fix += 3;
+ fragP->fr_var -= 3;
-static void
-check_and_update_trampolines (void)
-{
- struct trampoline_seg *ts = find_trampoline_seg (now_seg);
- struct trampoline_frag *tf = ts->trampoline_list.next;
- struct trampoline_frag *prev = &ts->trampoline_list;
+ /* Adjust the jump around this trampoline (if present). */
+ if (fragP->tc_frag_data.jump_around_fix)
+ fragP->tc_frag_data.jump_around_fix->fx_offset += 3;
- for ( ; tf; prev = tf, tf = tf->next)
+ /* Do we have room for more? */
+ if (xg_is_trampoline_frag_full (fragP))
{
- if (tf->fragP->fr_var < 3)
- {
- frag_wane (tf->fragP);
- prev->next = tf->next;
- tf->fragP = NULL;
- }
+ frag_wane (fragP);
+ fragP->fr_subtype = 0;
}
+
+ return fixP;
}
static int
-init_trampoline_frag (struct trampoline_frag *trampP)
+init_trampoline_frag (fragS *fp)
{
- fragS *fp = trampP->fragP;
int growth = 0;
if (fp->fr_fix == 0)
{
symbolS *lsym;
char label[10 + 2 * sizeof(fp)];
- sprintf (label, ".L0_TR_%p", fp);
- lsym = (symbolS *)local_symbol_make (label, now_seg, 0, fp);
+ sprintf (label, ".L0_TR_%p", fp);
+ lsym = (symbolS *) local_symbol_make (label, now_seg, fp, 0);
fp->fr_symbol = lsym;
- if (trampP->needs_jump_around)
+ if (fp->tc_frag_data.needs_jump_around)
{
- /* Add a jump around this block of jumps, in case
- control flows into this block. */
- fixS *fixP;
- TInsn insn;
- xtensa_format fmt;
- xtensa_isa isa = xtensa_default_isa;
-
- fp->tc_frag_data.is_insn = 1;
- /* Assemble a jump insn. */
- tinsn_init (&insn);
- insn.insn_type = ITYPE_INSN;
- insn.opcode = xtensa_j_opcode;
- insn.ntok = 1;
- set_expr_symbol_offset (&insn.tok[0], lsym, 3);
- fmt = xg_get_single_format (xtensa_j_opcode);
- tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf);
- xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf);
- xtensa_insnbuf_to_chars (isa, trampoline_buf, (unsigned char *)fp->fr_literal, 3);
- fp->fr_fix += 3;
- fp->fr_var -= 3;
+ fp->tc_frag_data.jump_around_fix = xg_append_jump (fp, lsym, 3);
growth = 3;
- fixP = fix_new (fp, 0, 3, lsym, 3, TRUE, BFD_RELOC_XTENSA_SLOT0_OP);
- trampP->fixP = fixP;
}
}
return growth;
}
-
static int
-add_jump_to_trampoline (struct trampoline_frag *trampP, fragS *origfrag)
+xg_get_single_symbol_slot (fragS *fragP)
+{
+ int i;
+ int slot = -1;
+
+ for (i = 0; i < MAX_SLOTS; ++i)
+ if (fragP->tc_frag_data.slot_symbols[i])
+ {
+ gas_assert (slot == -1);
+ slot = i;
+ }
+
+ gas_assert (slot >= 0 && slot < MAX_SLOTS);
+
+ return slot;
+}
+
+static fixS *
+add_jump_to_trampoline (fragS *tramp, fragS *origfrag)
{
- fragS *tramp = trampP->fragP;
+ int slot = xg_get_single_symbol_slot (origfrag);
fixS *fixP;
- int offset = tramp->fr_fix; /* Where to assemble the j insn. */
- TInsn insn;
- symbolS *lsym;
- symbolS *tsym;
- int toffset;
- xtensa_format fmt;
- xtensa_isa isa = xtensa_default_isa;
- int growth = 0;
- lsym = tramp->fr_symbol;
/* Assemble a jump to the target label in the trampoline frag. */
- tsym = origfrag->tc_frag_data.slot_symbols[0];
- toffset = origfrag-> tc_frag_data.slot_offsets[0];
- tinsn_init (&insn);
- insn.insn_type = ITYPE_INSN;
- insn.opcode = xtensa_j_opcode;
- insn.ntok = 1;
- set_expr_symbol_offset (&insn.tok[0], tsym, toffset);
- fmt = xg_get_single_format (xtensa_j_opcode);
- tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf);
- xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf);
- xtensa_insnbuf_to_chars (isa, trampoline_buf, (unsigned char *)tramp->fr_literal + offset, 3);
- tramp->fr_fix += 3;
- tramp->fr_var -= 3;
- growth = 3;
- /* add a fix-up for the trampoline jump. */
- fixP = fix_new (tramp, tramp->fr_fix - 3, 3, tsym, toffset, TRUE, BFD_RELOC_XTENSA_SLOT0_OP);
- /* Modify the jump at the start of this trampoline to point past the newly-added jump. */
- fixP = trampP->fixP;
- if (fixP)
- fixP->fx_offset += 3;
+ fixP = xg_append_jump (tramp,
+ origfrag->tc_frag_data.slot_symbols[slot],
+ origfrag->tc_frag_data.slot_offsets[slot]);
+
/* Modify the original j to point here. */
- origfrag->tc_frag_data.slot_symbols[0] = lsym;
- origfrag->tc_frag_data.slot_offsets[0] = tramp->fr_fix - 3;
+ origfrag->tc_frag_data.slot_symbols[slot] = tramp->fr_symbol;
+ origfrag->tc_frag_data.slot_offsets[slot] = tramp->fr_fix - 3;
+
/* If trampoline is full, remove it from the list. */
- check_and_update_trampolines ();
+ if (xg_is_trampoline_frag_full (tramp))
+ {
+ struct trampoline_seg *ts = find_trampoline_seg (now_seg);
+ size_t tr = xg_find_trampoline (&ts->index, tramp->fr_address);
- return growth;
+ gas_assert (ts->index.entry[tr] == tramp);
+ xg_remove_trampoline_from_index (&ts->index, tr);
+ }
+
+ return fixP;
}
xtensa_format fmt,
int slot,
int *stretched_p,
- bfd_boolean estimate_only)
+ bool estimate_only)
{
TInsn tinsn;
int old_size;
- bfd_boolean negatable_branch = FALSE;
- bfd_boolean branch_jmp_to_next = FALSE;
- bfd_boolean from_wide_insn = FALSE;
+ bool negatable_branch = false;
+ bool branch_jmp_to_next = false;
+ bool from_wide_insn = false;
xtensa_isa isa = xtensa_default_isa;
IStack istack;
offsetT frag_offset;
xg_clear_vinsn (&cur_vinsn);
vinsn_from_chars (&cur_vinsn, fragP->fr_opcode);
if (cur_vinsn.num_slots > 1)
- from_wide_insn = TRUE;
+ from_wide_insn = true;
tinsn = cur_vinsn.slots[slot];
tinsn_immed_from_frag (&tinsn, fragP, slot);
istack.insn[istack.ninsn - 2].opcode == xtensa_j_opcode)
{
TInsn *jinsn = &istack.insn[istack.ninsn - 2];
+ struct trampoline_seg *ts = find_trampoline_seg (segP);
+ struct trampoline_chain *tc = NULL;
- if (!xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset, total_text_diff))
+ if (ts &&
+ !xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset,
+ total_text_diff))
{
- struct trampoline_frag *tf = get_best_trampoline (jinsn, fragP);
+ int s = xg_get_single_symbol_slot (fragP);
+ addressT offset = fragP->tc_frag_data.slot_offsets[s];
+
+ tc = xg_find_best_eq_target (ts, fragP->fr_address,
+ &fragP->tc_frag_data.slot_symbols[s],
+ &offset);
+
+ if (!tc)
+ tc = xg_create_trampoline_chain (ts,
+ fragP->tc_frag_data.slot_symbols[s],
+ offset);
+ fragP->tc_frag_data.slot_offsets[s] = offset;
+ tinsn_immed_from_frag (jinsn, fragP, s);
+ }
+
+ if (!xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset,
+ total_text_diff))
+ {
+ fragS *tf = xg_find_best_trampoline_for_tinsn (jinsn, fragP);
if (tf)
{
- this_text_diff += init_trampoline_frag (tf);
- this_text_diff += add_jump_to_trampoline (tf, fragP);
+ fixS *fixP;
+
+ this_text_diff += init_trampoline_frag (tf) + 3;
+ fixP = add_jump_to_trampoline (tf, fragP);
+ xg_add_location_to_chain (tc, fixP->fx_frag->fr_symbol,
+ fixP->fx_where);
+ fragP->tc_frag_data.relax_seen = false;
}
else
{
convert_frag_align_next_opcode (fragS *fragp)
{
char *nop_buf; /* Location for Writing. */
- bfd_boolean use_no_density = fragp->tc_frag_data.is_no_density;
+ bool use_no_density = fragp->tc_frag_data.is_no_density;
addressT aligned_address;
offsetT fill_size;
int nop, nop_count;
tinsn_init (&single_target);
frag_offset = fragP->fr_opcode - fragP->fr_literal;
- if (! xg_is_single_relaxable_insn (&tinsn, &single_target, FALSE))
+ if (! xg_is_single_relaxable_insn (&tinsn, &single_target, false))
{
as_bad (_("unable to widen instruction"));
return;
size = xg_get_single_size (single_target.opcode);
xg_emit_insn_to_buf (&single_target, fragP->fr_opcode, fragP,
- frag_offset, TRUE);
+ frag_offset, true);
diff = size - old_size;
gas_assert (diff >= 0);
return;
}
assemble_nop (size, loc);
- fragP->tc_frag_data.is_insn = TRUE;
+ fragP->tc_frag_data.is_insn = true;
fragP->fr_var -= size;
fragP->fr_fix += size;
frag_wane (fragP);
static fixS *fix_new_exp_in_seg
(segT, subsegT, fragS *, int, int, expressionS *, int,
bfd_reloc_code_real_type);
-static void convert_frag_immed_finish_loop (segT, fragS *, TInsn *);
static void
convert_frag_immed (segT segP,
{
char *immed_instr = fragP->fr_opcode;
TInsn orig_tinsn;
- bfd_boolean expanded = FALSE;
- bfd_boolean branch_jmp_to_next = FALSE;
+ bool expanded = false;
+ bool branch_jmp_to_next = false;
char *fr_opcode = fragP->fr_opcode;
xtensa_isa isa = xtensa_default_isa;
- bfd_boolean from_wide_insn = FALSE;
+ bool from_wide_insn = false;
int bytes;
- bfd_boolean is_loop;
+ bool is_loop;
gas_assert (fr_opcode != NULL);
vinsn_from_chars (&cur_vinsn, fr_opcode);
if (cur_vinsn.num_slots > 1)
- from_wide_insn = TRUE;
+ from_wide_insn = true;
orig_tinsn = cur_vinsn.slots[slot];
tinsn_immed_from_frag (&orig_tinsn, fragP, slot);
build_nop (&cur_vinsn.slots[0], bytes);
fragP->fr_fix += fragP->tc_frag_data.text_expansion[0];
}
- vinsn_to_insnbuf (&cur_vinsn, fr_opcode, frag_now, TRUE);
+ vinsn_to_insnbuf (&cur_vinsn, fr_opcode, frag_now, true);
xtensa_insnbuf_to_chars
(isa, cur_vinsn.insnbuf, (unsigned char *) fr_opcode, 0);
fragP->fr_var = 0;
int diff;
symbolS *gen_label = NULL;
offsetT frag_offset;
- bfd_boolean first = TRUE;
+ bool first = true;
/* It does not fit. Find something that does and
convert immediately. */
target_offset += unreach->tc_frag_data.text_expansion[0];
}
gas_assert (gen_label == NULL);
- gen_label = symbol_new (FAKE_LABEL_NAME, now_seg,
+ gen_label = symbol_new (FAKE_LABEL_NAME, now_seg, fragP,
fr_opcode - fragP->fr_literal
- + target_offset, fragP);
+ + target_offset);
break;
case ITYPE_INSN:
if (first && from_wide_insn)
{
target_offset += xtensa_format_length (isa, fmt);
- first = FALSE;
+ first = false;
if (!opcode_fits_format_slot (tinsn->opcode, fmt, slot))
target_offset += xg_get_single_size (tinsn->opcode);
}
}
total_size = 0;
- first = TRUE;
+ first = true;
for (i = 0; i < istack.ninsn; i++)
{
TInsn *tinsn = &istack.insn[i];
/* Add a fixup. */
target_seg = S_GET_SEGMENT (lit_sym);
gas_assert (target_seg);
- reloc_type = map_operator_to_reloc (tinsn->tok[0].X_op, TRUE);
+ reloc_type = map_operator_to_reloc (tinsn->tok[0].X_op, true);
fix_new_exp_in_seg (target_seg, 0, lit_frag, 0, 4,
- &tinsn->tok[0], FALSE, reloc_type);
+ &tinsn->tok[0], false, reloc_type);
break;
case ITYPE_LABEL:
xg_resolve_literals (tinsn, lit_sym);
if (from_wide_insn && first)
{
- first = FALSE;
+ first = false;
if (opcode_fits_format_slot (tinsn->opcode, fmt, slot))
{
cur_vinsn.slots[slot] = *tinsn;
xtensa_format_slot_nop_opcode (isa, fmt, slot);
cur_vinsn.slots[slot].ntok = 0;
}
- vinsn_to_insnbuf (&cur_vinsn, immed_instr, fragP, TRUE);
+ 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;
+ fragP->tc_frag_data.is_insn = true;
size = xtensa_format_length (isa, fmt);
if (!opcode_fits_format_slot (tinsn->opcode, fmt, slot))
{
xg_emit_insn_to_buf
(tinsn, immed_instr + size, fragP,
- immed_instr - fragP->fr_literal + size, TRUE);
+ immed_instr - fragP->fr_literal + size, true);
size += xg_get_single_size (tinsn->opcode);
}
}
{
size = xg_get_single_size (tinsn->opcode);
xg_emit_insn_to_buf (tinsn, immed_instr, fragP,
- immed_instr - fragP->fr_literal, TRUE);
+ immed_instr - fragP->fr_literal, true);
}
immed_instr += size;
total_size += size;
diff = total_size - old_size;
gas_assert (diff >= 0);
if (diff != 0)
- expanded = TRUE;
+ expanded = true;
gas_assert (diff <= fragP->fr_var);
fragP->fr_var -= diff;
fragP->fr_fix += diff;
}
}
- if (expanded && xtensa_opcode_is_loop (isa, orig_tinsn.opcode) == 1)
- convert_frag_immed_finish_loop (segP, fragP, &orig_tinsn);
-
if (expanded && is_direct_call_opcode (orig_tinsn.opcode))
{
/* Add an expansion note on the expanded instruction. */
fix_new_exp_in_seg (now_seg, 0, fragP, fr_opcode - fragP->fr_literal, 4,
- &orig_tinsn.tok[0], TRUE,
+ &orig_tinsn.tok[0], true,
BFD_RELOC_XTENSA_ASM_EXPAND);
}
}
}
-/* Relax a loop instruction so that it can span loop >256 bytes.
-
- loop as, .L1
- .L0:
- rsr as, LEND
- wsr as, LBEG
- addi as, as, lo8 (label-.L1)
- addmi as, as, mid8 (label-.L1)
- wsr as, LEND
- isync
- rsr as, LCOUNT
- addi as, as, 1
- .L1:
- <<body>>
- label:
-*/
-
-static void
-convert_frag_immed_finish_loop (segT segP, fragS *fragP, TInsn *tinsn)
-{
- TInsn loop_insn;
- TInsn addi_insn;
- TInsn addmi_insn;
- unsigned long target;
- static xtensa_insnbuf insnbuf = NULL;
- unsigned int loop_length, loop_length_hi, loop_length_lo;
- xtensa_isa isa = xtensa_default_isa;
- addressT loop_offset;
- addressT addi_offset = 9;
- addressT addmi_offset = 12;
- fragS *next_fragP;
- int target_count;
-
- if (!insnbuf)
- insnbuf = xtensa_insnbuf_alloc (isa);
-
- /* Get the loop offset. */
- loop_offset = get_expanded_loop_offset (tinsn->opcode);
-
- /* Validate that there really is a LOOP at the loop_offset. Because
- loops are not bundleable, we can assume that the instruction will be
- in slot 0. */
- tinsn_from_chars (&loop_insn, fragP->fr_opcode + loop_offset, 0);
- tinsn_immed_from_frag (&loop_insn, fragP, 0);
-
- gas_assert (xtensa_opcode_is_loop (isa, loop_insn.opcode) == 1);
- addi_offset += loop_offset;
- addmi_offset += loop_offset;
-
- gas_assert (tinsn->ntok == 2);
- if (tinsn->tok[1].X_op == O_constant)
- target = tinsn->tok[1].X_add_number;
- else if (tinsn->tok[1].X_op == O_symbol)
- {
- /* Find the fragment. */
- symbolS *sym = tinsn->tok[1].X_add_symbol;
- gas_assert (S_GET_SEGMENT (sym) == segP
- || S_GET_SEGMENT (sym) == absolute_section);
- target = (S_GET_VALUE (sym) + tinsn->tok[1].X_add_number);
- }
- else
- {
- as_bad (_("invalid expression evaluation type %d"), tinsn->tok[1].X_op);
- target = 0;
- }
-
- loop_length = target - (fragP->fr_address + fragP->fr_fix);
- loop_length_hi = loop_length & ~0x0ff;
- loop_length_lo = loop_length & 0x0ff;
- if (loop_length_lo >= 128)
- {
- loop_length_lo -= 256;
- loop_length_hi += 256;
- }
-
- /* Because addmi sign-extends the immediate, 'loop_length_hi' can be at most
- 32512. If the loop is larger than that, then we just fail. */
- if (loop_length_hi > 32512)
- as_bad_where (fragP->fr_file, fragP->fr_line,
- _("loop too long for LOOP instruction"));
-
- tinsn_from_chars (&addi_insn, fragP->fr_opcode + addi_offset, 0);
- gas_assert (addi_insn.opcode == xtensa_addi_opcode);
-
- tinsn_from_chars (&addmi_insn, fragP->fr_opcode + addmi_offset, 0);
- gas_assert (addmi_insn.opcode == xtensa_addmi_opcode);
-
- set_expr_const (&addi_insn.tok[2], loop_length_lo);
- tinsn_to_insnbuf (&addi_insn, insnbuf);
-
- fragP->tc_frag_data.is_insn = TRUE;
- xtensa_insnbuf_to_chars
- (isa, insnbuf, (unsigned char *) fragP->fr_opcode + addi_offset, 0);
-
- set_expr_const (&addmi_insn.tok[2], loop_length_hi);
- tinsn_to_insnbuf (&addmi_insn, insnbuf);
- xtensa_insnbuf_to_chars
- (isa, insnbuf, (unsigned char *) fragP->fr_opcode + addmi_offset, 0);
-
- /* Walk through all of the frags from here to the loop end
- and mark them as no_transform to keep them from being modified
- by the linker. If we ever have a relocation for the
- addi/addmi of the difference of two symbols we can remove this. */
-
- target_count = 0;
- for (next_fragP = fragP; next_fragP != NULL;
- next_fragP = next_fragP->fr_next)
- {
- next_fragP->tc_frag_data.is_no_transform = TRUE;
- if (next_fragP->tc_frag_data.is_loop_target)
- target_count++;
- if (target_count == 2)
- break;
- }
-}
-
\f
/* A map that keeps information on a per-subsegment basis. This is
maintained during initial assembly, but is invalid once the
set_last_insn_flags (segT seg,
subsegT subseg,
unsigned fl,
- bfd_boolean val)
+ bool val)
{
subseg_map *subseg_e = get_subseg_info (seg, subseg);
if (! subseg_e)
static void mark_literal_frags (seg_list *);
static void
-xtensa_move_literals (void)
+xg_promote_candidate_litpool (struct litpool_seg *lps,
+ struct litpool_frag *lp)
{
- seg_list *segment;
- frchainS *frchain_from, *frchain_to;
- fragS *search_frag, *next_frag, *literal_pool, *insert_after;
- fragS **frag_splice;
- emit_state state;
- segT dest_seg;
- fixS *fix, *next_fix, **fix_splice;
- sym_list *lit;
- struct litpool_seg *lps;
- const char *init_name = INIT_SECTION_NAME;
- const char *fini_name = FINI_SECTION_NAME;
- int init_name_len = strlen(init_name);
- int fini_name_len = strlen(fini_name);
+ fragS *poolbeg;
+ fragS *poolend;
+ symbolS *lsym;
+ char label[10 + 2 * sizeof (fragS *)];
- mark_literal_frags (literal_head->next);
+ poolbeg = lp->fragP;
+ lp->priority = 1;
+ poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN;
+ poolend = poolbeg->fr_next;
+ gas_assert (poolend->fr_type == rs_machine_dependent &&
+ poolend->fr_subtype == RELAX_LITERAL_POOL_END);
+ /* Create a local symbol pointing to the
+ end of the pool. */
+ sprintf (label, ".L0_LT_%p", poolbeg);
+ lsym = (symbolS *) local_symbol_make (label, lps->seg, poolend, 0);
+ poolbeg->fr_symbol = lsym;
+ /* Rest is done in xtensa_relax_frag. */
+}
- if (use_literal_section)
- return;
+static struct litpool_frag *xg_find_litpool (struct litpool_seg *lps,
+ struct litpool_frag *lpf,
+ addressT addr)
+{
+ struct litpool_frag *lp = lpf->prev;
- /* Assign addresses (rough estimates) to the potential literal pool locations
- and create new ones if the gaps are too large. */
+ gas_assert (lp->fragP);
+
+ while (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+ {
+ lp = lp->prev;
+ if (lp->fragP == NULL)
+ {
+ /* End of list; have to bite the bullet.
+ Take the nearest. */
+ lp = lpf->prev;
+ break;
+ }
+ /* Does it (conservatively) reach? */
+ if (addr - lp->addr <= 128 * 1024)
+ {
+ if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
+ lp->literal_count < MAX_POOL_LITERALS)
+ {
+ /* Found a good one. */
+ break;
+ }
+ else if (lp->prev->fragP &&
+ addr - lp->prev->addr > 128 * 1024 &&
+ lp->prev->literal_count < MAX_POOL_LITERALS)
+ {
+ /* This is still a "candidate" but the next one
+ will be too far away, so revert to the nearest
+ one, convert it and add the jump around. */
+ lp = lpf->prev;
+ break;
+ }
+ }
+ }
+
+ if (lp->literal_count >= MAX_POOL_LITERALS)
+ {
+ lp = lpf->prev;
+ while (lp && lp->fragP && lp->literal_count >= MAX_POOL_LITERALS)
+ {
+ lp = lp->prev;
+ }
+ gas_assert (lp);
+ }
+
+ gas_assert (lp && lp->fragP && lp->literal_count < MAX_POOL_LITERALS);
+ ++lp->literal_count;
+
+ /* Convert candidate and add the jump around. */
+ if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+ xg_promote_candidate_litpool (lps, lp);
+
+ return lp;
+}
+
+static bool xtensa_is_init_fini (segT seg)
+{
+ if (!seg)
+ return 0;
+ return strcmp (segment_name (seg), INIT_SECTION_NAME) == 0
+ || strcmp (segment_name (seg), FINI_SECTION_NAME) == 0;
+}
+
+static void
+xtensa_assign_litpool_addresses (void)
+{
+ struct litpool_seg *lps;
for (lps = litpool_seg_list.next; lps; lps = lps->next)
{
struct litpool_frag *lpf = lps->frag_list.next;
addressT addr = 0;
+ if (xtensa_is_init_fini (lps->seg))
+ continue;
+
for ( ; frchP; frchP = frchP->frch_next)
{
fragS *fragP;
int slot;
for (slot = 0; slot < MAX_SLOTS; slot++)
{
- if (fragP->tc_frag_data.literal_frags[slot])
+ fragS *litfrag = fragP->tc_frag_data.literal_frags[slot];
+
+ if (litfrag
+ && litfrag->tc_frag_data.is_literal
+ && !litfrag->tc_frag_data.literal_frag)
{
- /* L32R; point its literal to the nearest litpool
- preferring non-"candidate" positions to avoid
- the jump-around. */
- fragS *litfrag = fragP->tc_frag_data.literal_frags[slot];
- struct litpool_frag *lp = lpf->prev;
- if (!lp->fragP)
- {
- break;
- }
- while (lp->fragP->fr_subtype ==
- RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
- {
- lp = lp->prev;
- if (lp->fragP == NULL)
- {
- /* End of list; have to bite the bullet.
- Take the nearest. */
- lp = lpf->prev;
- break;
- }
- /* Does it (conservatively) reach? */
- if (addr - lp->addr <= 128 * 1024)
- {
- if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
- {
- /* Found a good one. */
- break;
- }
- else if (lp->prev->fragP &&
- addr - lp->prev->addr > 128 * 1024)
- {
- /* This is still a "candidate" but the next one
- will be too far away, so revert to the nearest
- one, convert it and add the jump around. */
- fragS *poolbeg;
- fragS *poolend;
- symbolS *lsym;
- char label[10 + 2 * sizeof (fragS *)];
- lp = lpf->prev;
- poolbeg = lp->fragP;
- lp->priority = 1;
- poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN;
- poolend = poolbeg->fr_next;
- gas_assert (poolend->fr_type == rs_machine_dependent &&
- poolend->fr_subtype == RELAX_LITERAL_POOL_END);
- /* Create a local symbol pointing to the
- end of the pool. */
- sprintf (label, ".L0_LT_%p", poolbeg);
- lsym = (symbolS *)local_symbol_make (label, lps->seg,
- 0, poolend);
- poolbeg->fr_symbol = lsym;
- /* Rest is done in xtensa_relax_frag. */
- }
- }
- }
- if (! litfrag->tc_frag_data.literal_frag)
- {
- /* Take earliest use of this literal to avoid
- forward refs. */
- litfrag->tc_frag_data.literal_frag = lp->fragP;
- }
+ /* L32R referring .literal or generated as a result
+ of relaxation. Point its literal to the nearest
+ litpool preferring non-"candidate" positions to
+ avoid the jump-around. */
+
+ struct litpool_frag *lp;
+
+ lp = xg_find_litpool (lps, lpf, addr);
+ /* Take earliest use of this literal to avoid
+ forward refs. */
+ litfrag->tc_frag_data.literal_frag = lp->fragP;
}
}
}
}
}
}
+}
+static void
+xtensa_move_literals (void)
+{
+ seg_list *segment;
+ frchainS *frchain_from, *frchain_to;
+ fragS *search_frag, *next_frag, *literal_pool, *insert_after;
+ fragS **frag_splice;
+ emit_state state;
+ segT dest_seg;
+ fixS *fix, *next_fix, **fix_splice;
+ sym_list *lit;
+ const char *init_name = INIT_SECTION_NAME;
+ const char *fini_name = FINI_SECTION_NAME;
+ int init_name_len = strlen(init_name);
+ int fini_name_len = strlen(fini_name);
+
+ mark_literal_frags (literal_head->next);
+
+ if (use_literal_section)
+ return;
+
+ /* Assign addresses (rough estimates) to the potential literal pool locations
+ and create new ones if the gaps are too large. */
+
+ xtensa_assign_litpool_addresses ();
+
+ /* Walk through the literal segments. */
for (segment = literal_head->next; segment; segment = segment->next)
{
const char *seg_name = segment_name (segment->seg);
}
if (!search_frag)
- {
- search_frag = frchain_from->frch_root;
- as_bad_where (search_frag->fr_file, search_frag->fr_line,
- _("literal pool location required for text-section-literals; specify with .literal_position"));
- continue;
- }
+ continue;
gas_assert (search_frag->tc_frag_data.literal_frag->fr_subtype
== RELAX_LITERAL_POOL_BEGIN);
/* First, move the frag out of the literal section and
to the appropriate place. */
- /* Insert an aligmnent frag at start of pool. */
+ /* Insert an alignment frag at start of pool. */
if (literal_pool->fr_next->fr_type == rs_machine_dependent &&
literal_pool->fr_next->fr_subtype == RELAX_LITERAL_POOL_END)
{
search_frag = frchain_from->frch_root;
while (search_frag)
{
- search_frag->tc_frag_data.is_literal = TRUE;
+ search_frag->tc_frag_data.is_literal = true;
search_frag = search_frag->fr_next;
}
segment = segment->next;
{
if (directive_state[directive_absolute_literals])
{
- segT lit4_seg = cache_literal_section (TRUE);
+ segT lit4_seg = cache_literal_section (true);
xtensa_switch_section_emit_state (result, lit4_seg, 0);
}
else
static void
xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
{
- static bfd_boolean recursive = FALSE;
fragS *pool_location = get_literal_pool_location (now_seg);
segT lit_seg;
- bfd_boolean is_init =
- (now_seg && !strcmp (segment_name (now_seg), INIT_SECTION_NAME));
- bfd_boolean is_fini =
- (now_seg && !strcmp (segment_name (now_seg), FINI_SECTION_NAME));
+ bool is_init_fini = xtensa_is_init_fini (now_seg);
if (pool_location == NULL
&& !use_literal_section
- && !recursive
- && !is_init && ! is_fini)
+ && !is_init_fini)
{
if (!auto_litpools)
{
as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
}
-
- /* When we mark a literal pool location, we want to put a frag in
- the literal pool that points to it. But to do that, we want to
- switch_to_literal_fragment. But literal sections don't have
- literal pools, so their location is always null, so we would
- recurse forever. This is kind of hacky, but it works. */
-
- recursive = TRUE;
- xtensa_mark_literal_pool_location ();
- recursive = FALSE;
+ xtensa_maybe_create_literal_pool_frag (true, true);
+ pool_location = get_literal_pool_location (now_seg);
}
- lit_seg = cache_literal_section (FALSE);
+ lit_seg = cache_literal_section (false);
xtensa_switch_section_emit_state (result, lit_seg, 0);
if (!use_literal_section
- && !is_init && !is_fini
+ && !is_init_fini
&& get_literal_pool_location (now_seg) != pool_location)
{
/* Close whatever frag is there. */
/* Predicate function used to look up a section in a particular group. */
-static bfd_boolean
+static bool
match_section_group (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
{
const char *gname = inf;
The result may be cached in the default_lit_sections structure. */
static segT
-cache_literal_section (bfd_boolean use_abs_literals)
+cache_literal_section (bool use_abs_literals)
{
const char *text_name, *group_name = 0;
const char *base_name, *suffix;
segT *pcached;
segT seg, current_section;
int current_subsec;
- bfd_boolean linkonce = FALSE;
+ bool linkonce = false;
/* Save the current section/subsection. */
current_section = now_seg;
name = concat (".gnu.linkonce", base_name, suffix ? suffix : "",
(char *) NULL);
- linkonce = TRUE;
+ linkonce = true;
}
else
{
size_t len = strlen (text_name);
if (len >= 5
&& (strcmp (text_name + len - 5, ".text") == 0
- || strncmp (text_name, ".text", 5) == 0))
+ || startswith (text_name, ".text")))
len -= 5;
- name = xmalloc (len + strlen (base_name) + 1);
- if (strncmp (text_name, ".text", 5) == 0)
+ name = XNEWVEC (char, len + strlen (base_name) + 1);
+ if (startswith (text_name, ".text"))
{
strcpy (name, base_name);
strcat (name, text_name + 5);
elf_group_name (seg) = group_name;
- bfd_set_section_flags (stdoutput, seg, flags);
- bfd_set_section_alignment (stdoutput, seg, 2);
+ bfd_set_section_flags (seg, flags);
+ bfd_set_section_alignment (seg, 2);
}
*pcached = seg;
#define XTENSA_LIT_SEC_NAME ".xt.lit"
#define XTENSA_PROP_SEC_NAME ".xt.prop"
-typedef bfd_boolean (*frag_predicate) (const fragS *);
+typedef bool (*frag_predicate) (const fragS *);
typedef void (*frag_flags_fn) (const fragS *, frag_flags *);
-static bfd_boolean get_frag_is_literal (const fragS *);
+static bool get_frag_is_literal (const fragS *);
static void xtensa_create_property_segments
(frag_predicate, frag_predicate, const char *, xt_section_type);
static void xtensa_create_xproperty_segments
(frag_flags_fn, const char *, xt_section_type);
-static bfd_boolean exclude_section_from_property_tables (segT);
-static bfd_boolean section_has_property (segT, frag_predicate);
-static bfd_boolean section_has_xproperty (segT, frag_flags_fn);
+static bool exclude_section_from_property_tables (segT);
+static bool section_has_property (segT, frag_predicate);
+static bool section_has_xproperty (segT, frag_flags_fn);
static void add_xt_block_frags
(segT, xtensa_block_info **, frag_predicate, frag_predicate);
-static bfd_boolean xtensa_frag_flags_is_empty (const frag_flags *);
+static bool xtensa_frag_flags_is_empty (const frag_flags *);
static void xtensa_frag_flags_init (frag_flags *);
static void get_frag_property_flags (const fragS *, frag_flags *);
static flagword frag_flags_to_number (const frag_flags *);
/* This function is only meaningful after xtensa_move_literals. */
-static bfd_boolean
+static bool
get_frag_is_literal (const fragS *fragP)
{
gas_assert (fragP != NULL);
num_recs++;
rec_size = num_recs * 8;
- bfd_set_section_size (stdoutput, sec, rec_size);
+ bfd_set_section_size (sec, rec_size);
if (num_recs)
{
fix = fix_new (frag_now, i * 8, 4,
section_symbol (cur_block->sec),
cur_block->offset,
- FALSE, BFD_RELOC_32);
+ false, BFD_RELOC_32);
fix->fx_file = "<internal>";
fix->fx_line = 0;
num_recs++;
rec_size = num_recs * (8 + 4);
- bfd_set_section_size (stdoutput, sec, rec_size);
+ bfd_set_section_size (sec, rec_size);
/* elf_section_data (sec)->this_hdr.sh_entsize = 12; */
if (num_recs)
fix = fix_new (frag_now, i * 12, 4,
section_symbol (cur_block->sec),
cur_block->offset,
- FALSE, BFD_RELOC_32);
+ false, BFD_RELOC_32);
fix->fx_file = "<internal>";
fix->fx_line = 0;
}
-static bfd_boolean
+static bool
exclude_section_from_property_tables (segT sec)
{
- flagword flags = bfd_get_section_flags (stdoutput, sec);
+ flagword flags = bfd_section_flags (sec);
/* Sections that don't contribute to the memory footprint are excluded. */
if ((flags & SEC_DEBUGGING)
|| !(flags & SEC_ALLOC)
|| (flags & SEC_MERGE))
- return TRUE;
+ return true;
/* Linker cie and fde optimizations mess up property entries for
eh_frame sections, but there is nothing inside them relevant to
property tables anyway. */
if (strcmp (sec->name, ".eh_frame") == 0)
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
-static bfd_boolean
+static bool
section_has_property (segT sec, frag_predicate property_function)
{
segment_info_type *seginfo = seg_info (sec);
{
if (property_function (fragP)
&& (fragP->fr_type != rs_fill || fragP->fr_fix != 0))
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
-static bfd_boolean
+static bool
section_has_xproperty (segT sec, frag_flags_fn property_function)
{
segment_info_type *seginfo = seg_info (sec);
frag_flags prop_flags;
property_function (fragP, &prop_flags);
if (!xtensa_frag_flags_is_empty (&prop_flags))
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
/* Break the encapsulation of add_xt_prop_frags here. */
-static bfd_boolean
+static bool
xtensa_frag_flags_is_empty (const frag_flags *prop_flags)
{
if (prop_flags->is_literal
|| prop_flags->is_insn
|| prop_flags->is_data
|| prop_flags->is_unreachable)
- return FALSE;
- return TRUE;
+ return false;
+ return true;
}
{
xtensa_frag_flags_init (prop_flags);
if (fragP->tc_frag_data.is_literal)
- prop_flags->is_literal = TRUE;
+ prop_flags->is_literal = true;
if (fragP->tc_frag_data.is_specific_opcode
|| fragP->tc_frag_data.is_no_transform)
{
- prop_flags->is_no_transform = TRUE;
+ prop_flags->is_no_transform = true;
if (xtensa_frag_flags_is_empty (prop_flags))
- prop_flags->is_data = TRUE;
+ prop_flags->is_data = true;
}
if (fragP->tc_frag_data.is_unreachable)
- prop_flags->is_unreachable = TRUE;
+ prop_flags->is_unreachable = true;
else if (fragP->tc_frag_data.is_insn)
{
- prop_flags->is_insn = TRUE;
+ prop_flags->is_insn = true;
if (fragP->tc_frag_data.is_loop_target)
- prop_flags->insn.is_loop_target = TRUE;
+ prop_flags->insn.is_loop_target = true;
if (fragP->tc_frag_data.is_branch_target)
- prop_flags->insn.is_branch_target = TRUE;
+ prop_flags->insn.is_branch_target = true;
if (fragP->tc_frag_data.is_no_density)
- prop_flags->insn.is_no_density = TRUE;
+ prop_flags->insn.is_no_density = true;
if (fragP->tc_frag_data.use_absolute_literals)
- prop_flags->insn.is_abslit = TRUE;
+ prop_flags->insn.is_abslit = true;
}
if (fragP->tc_frag_data.is_align)
{
- prop_flags->is_align = TRUE;
+ prop_flags->is_align = true;
prop_flags->alignment = fragP->tc_frag_data.alignment;
if (xtensa_frag_flags_is_empty (prop_flags))
- prop_flags->is_data = TRUE;
+ prop_flags->is_data = true;
}
}
}
-static bfd_boolean
+static bool
xtensa_frag_flags_combinable (const frag_flags *prop_flags_1,
const frag_flags *prop_flags_2)
{
/* Cannot combine with an end marker. */
if (prop_flags_1->is_literal != prop_flags_2->is_literal)
- return FALSE;
+ return false;
if (prop_flags_1->is_insn != prop_flags_2->is_insn)
- return FALSE;
+ return false;
if (prop_flags_1->is_data != prop_flags_2->is_data)
- return FALSE;
+ return false;
if (prop_flags_1->is_insn)
{
/* Properties of the beginning of the frag. */
if (prop_flags_2->insn.is_loop_target)
- return FALSE;
+ return false;
if (prop_flags_2->insn.is_branch_target)
- return FALSE;
+ return false;
if (prop_flags_1->insn.is_no_density !=
prop_flags_2->insn.is_no_density)
- return FALSE;
+ return false;
if (prop_flags_1->is_no_transform !=
prop_flags_2->is_no_transform)
- return FALSE;
+ return false;
if (prop_flags_1->insn.is_no_reorder !=
prop_flags_2->insn.is_no_reorder)
- return FALSE;
+ return false;
if (prop_flags_1->insn.is_abslit !=
prop_flags_2->insn.is_abslit)
- return FALSE;
+ return false;
}
if (prop_flags_1->is_align)
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
}
-static bfd_boolean
+static bool
xtensa_xt_block_combine (xtensa_block_info *xt_block,
const xtensa_block_info *xt_block_2)
{
if (xt_block->sec != xt_block_2->sec)
- return FALSE;
+ return false;
if (xt_block->offset + xt_block_aligned_size (xt_block)
!= xt_block_2->offset)
- return FALSE;
+ return false;
if (xt_block_2->size == 0
&& (!xt_block_2->flags.is_unreachable
{
/* Nothing needed. */
if (xt_block->flags.alignment >= xt_block_2->flags.alignment)
- return TRUE;
+ return true;
}
else
{
xt_block->flags.is_align = xt_block_2->flags.is_align;
xt_block->flags.alignment = xt_block_2->flags.alignment;
}
- return TRUE;
+ return true;
}
}
if (!xtensa_frag_flags_combinable (&xt_block->flags,
&xt_block_2->flags))
- return FALSE;
+ return false;
xt_block->size += xt_block_2->size;
if (xt_block_2->flags.is_align)
{
- xt_block->flags.is_align = TRUE;
+ xt_block->flags.is_align = true;
xt_block->flags.alignment = xt_block_2->flags.alignment;
}
- return TRUE;
+ return true;
}
}
-bfd_boolean
+bool
opcode_fits_format_slot (xtensa_opcode opcode, xtensa_format fmt, int slot)
{
return bit_is_set (slot, op_placement_table[opcode].slots[fmt]);
}
-bfd_boolean
+bool
istack_empty (IStack *stack)
{
return (stack->ninsn == 0);
}
-bfd_boolean
+bool
istack_full (IStack *stack)
{
return (stack->ninsn == MAX_ISTACK);
/* Return TRUE if ANY of the operands in the insn are symbolic. */
-static bfd_boolean
+static bool
tinsn_has_symbolic_operands (const TInsn *insn)
{
int i;
case O_constant:
break;
default:
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
-bfd_boolean
+bool
tinsn_has_invalid_symbolic_operands (const TInsn *insn)
{
xtensa_isa isa = xtensa_default_isa;
&& insn->opcode != xtensa_const16_opcode))
{
as_bad (_("invalid symbolic operand"));
- return TRUE;
+ return true;
}
}
}
- return FALSE;
+ return false;
}
The relaxation only handles expressions that
boil down to SYMBOL + OFFSET. */
-static bfd_boolean
+static bool
tinsn_has_complex_operands (const TInsn *insn)
{
int i;
case O_hi16:
break;
default:
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
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
+static bool
tinsn_to_slotbuf (xtensa_format fmt,
int slot,
TInsn *tinsn,
{
xtensa_isa isa = xtensa_default_isa;
xtensa_opcode opcode = tinsn->opcode;
- bfd_boolean has_fixup = FALSE;
+ bool has_fixup = false;
int noperands = xtensa_opcode_num_operands (isa, opcode);
int i;
{
as_bad (_("cannot encode opcode \"%s\" in the given format \"%s\""),
xtensa_opcode_name (isa, opcode), xtensa_format_name (isa, fmt));
- return FALSE;
+ return false;
}
for (i = 0; i < noperands; i++)
break;
default:
- has_fixup = TRUE;
+ has_fixup = true;
break;
}
}
Return TRUE if there is a symbol in the immediate field. See also the
assumptions listed for tinsn_to_slotbuf. */
-static bfd_boolean
+static bool
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;
+ bool has_fixup = false;
int i;
if (!slotbuf)
/* Check the instruction arguments. Return TRUE on failure. */
-static bfd_boolean
+static bool
tinsn_check_arguments (const TInsn *insn)
{
xtensa_isa isa = xtensa_default_isa;
if (opcode == XTENSA_UNDEFINED)
{
as_bad (_("invalid opcode"));
- return TRUE;
+ return true;
}
if (xtensa_opcode_num_operands (isa, opcode) > insn->ntok)
{
as_bad (_("too few operands"));
- return TRUE;
+ return true;
}
if (xtensa_opcode_num_operands (isa, opcode) < insn->ntok)
{
as_bad (_("too many operands"));
- return TRUE;
+ return true;
}
/* Check registers. */
if (t1_inout != 'i' && t2_inout != 'i')
{
as_bad (_("multiple writes to the same register"));
- return TRUE;
+ return true;
}
}
}
}
}
- return FALSE;
+ return false;
}
/* Find the immed. */
tinsn_init (tinsn);
tinsn->insn_type = ITYPE_INSN;
- tinsn->is_specific_opcode = FALSE; /* must not be specific */
+ tinsn->is_specific_opcode = false; /* must not be specific */
tinsn->opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf);
tinsn->ntok = xtensa_opcode_num_operands (isa, tinsn->opcode);
for (i = 0; i < tinsn->ntok; i++)
v->format = XTENSA_UNDEFINED;
v->num_slots = 0;
- v->inside_bundle = FALSE;
+ v->inside_bundle = false;
if (xt_saved_debug_type != DEBUG_NONE)
debug_type = xt_saved_debug_type;
}
-static bfd_boolean
+static bool
vinsn_has_specific_opcodes (vliw_insn *v)
{
int i;
for (i = 0; i < v->num_slots; i++)
{
if (v->slots[i].is_specific_opcode)
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
/* 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
+static bool
vinsn_to_insnbuf (vliw_insn *vinsn,
char *frag_offset,
fragS *fragP,
- bfd_boolean record_fixup)
+ bool record_fixup)
{
xtensa_isa isa = xtensa_default_isa;
xtensa_format fmt = vinsn->format;
xtensa_insnbuf insnbuf = vinsn->insnbuf;
int slot;
- bfd_boolean has_fixup = FALSE;
+ bool has_fixup = false;
xtensa_format_encode (isa, fmt, insnbuf);
{
TInsn *tinsn = &vinsn->slots[slot];
expressionS *extra_arg = &tinsn->extra_arg;
- bfd_boolean tinsn_has_fixup =
+ bool tinsn_has_fixup =
tinsn_to_slotbuf (vinsn->format, slot, tinsn,
vinsn->slotbuf[slot]);
fix_new (fragP, frag_offset - fragP->fr_literal,
xtensa_format_length (isa, fmt),
extra_arg->X_add_symbol, extra_arg->X_add_number,
- FALSE, map_operator_to_reloc (extra_arg->X_op, FALSE));
+ false, map_operator_to_reloc (extra_arg->X_op, false));
}
if (tinsn_has_fixup)
{
int i;
xtensa_opcode opcode = tinsn->opcode;
int noperands = xtensa_opcode_num_operands (isa, opcode);
- has_fixup = TRUE;
+ has_fixup = true;
for (i = 0; i < noperands; i++)
{
/* Return TRUE if the expression is an integer constant. */
-bfd_boolean
+bool
expr_is_const (const expressionS *s)
{
return (s->X_op == O_constant);
}
-bfd_boolean
+bool
expr_is_register (const expressionS *s)
{
return (s->X_op == O_register);
/* Return TRUE if the two expressions are equal. */
-bfd_boolean
+bool
expr_is_equal (expressionS *s1, expressionS *s2)
{
if (s1->X_op != s2->X_op)
- return FALSE;
+ return false;
if (s1->X_add_symbol != s2->X_add_symbol)
- return FALSE;
+ return false;
if (s1->X_op_symbol != s2->X_op_symbol)
- return FALSE;
+ return false;
if (s1->X_add_number != s2->X_add_number)
- return FALSE;
- return TRUE;
+ return false;
+ return true;
}