/* tc-xtensa.c -- Assemble Xtensa instructions.
- Copyright 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2003-2022 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
-#include <limits.h>
#include "as.h"
+#include <limits.h>
#include "sb.h"
#include "safe-ctype.h"
#include "tc-xtensa.h"
#include "subsegs.h"
#include "xtensa-relax.h"
-#include "xtensa-istack.h"
#include "dwarf2dbg.h"
-#include "struc-symbol.h"
+#include "xtensa-istack.h"
#include "xtensa-config.h"
+#include "elf/xtensa.h"
/* Provide default values for new configuration settings. */
-#ifndef XSHAL_ABI
-#define XSHAL_ABI 0
+#ifndef XTHAL_ABI_WINDOWED
+#define XTHAL_ABI_WINDOWED 0
+#endif
+
+#ifndef XTHAL_ABI_CALL0
+#define XTHAL_ABI_CALL0 1
+#endif
+
+#ifndef XTENSA_MARCH_EARLIEST
+#define XTENSA_MARCH_EARLIEST 0
#endif
#ifndef uint32
/* 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;
-/* Maximum width we would pad an unreachable frag to get alignment. */
-#define UNREACHABLE_MAX_WIDTH 8
+static unsigned microarch_earliest;
static vliw_insn cur_vinsn;
-unsigned xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH;
+unsigned xtensa_num_pipe_stages;
+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_end = 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))
#define O_pltrel O_md1 /* like O_symbol but use a PLT reloc */
#define O_hi16 O_md2 /* use high 16 bits of symbolic value */
#define O_lo16 O_md3 /* use low 16 bits of symbolic value */
+#define O_pcrel O_md4 /* value is a PC-relative offset */
+#define O_tlsfunc O_md5 /* TLS_FUNC/TLSDESC_FN relocation */
+#define O_tlsarg O_md6 /* TLS_ARG/TLSDESC_ARG relocation */
+#define O_tlscall O_md7 /* TLS_CALL relocation */
+#define O_tpoff O_md8 /* TPOFF relocation */
+#define O_dtpoff O_md9 /* DTPOFF relocation */
struct suffix_reloc_map
{
- char *suffix;
+ 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 ("l", BFD_RELOC_LO16, O_lo16),
SUFFIX_MAP ("h", BFD_RELOC_HI16, O_hi16),
SUFFIX_MAP ("plt", BFD_RELOC_XTENSA_PLT, O_pltrel),
- { (char *) 0, 0, BFD_RELOC_UNUSED, 0 }
+ SUFFIX_MAP ("pcrel", BFD_RELOC_32_PCREL, O_pcrel),
+ SUFFIX_MAP ("tlsfunc", BFD_RELOC_XTENSA_TLS_FUNC, O_tlsfunc),
+ SUFFIX_MAP ("tlsarg", BFD_RELOC_XTENSA_TLS_ARG, O_tlsarg),
+ 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),
};
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[] =
+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
+ in a segment. */
+struct litpool_frag
{
- 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
+ struct litpool_frag *next;
+ struct litpool_frag *prev;
+ fragS *fragP;
+ 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. */
+struct litpool_seg
+{
+ struct litpool_seg *next;
+ asection *seg;
+ struct litpool_frag frag_list;
+ int frag_count; /* since last litpool location */
};
+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. */
static void xtensa_literal_pseudo (int);
static void xtensa_frequency_pseudo (int);
static void xtensa_elf_cons (int);
+static void xtensa_leb128 (int);
/* Parsing and Idiom Translation. */
/* 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 bool use_trampolines = true;
+static void xtensa_check_frag_count (void);
+static void xtensa_create_trampoline_frag (bool);
+static void xtensa_maybe_create_trampoline_frag (void);
+struct trampoline_frag;
+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_get_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 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. */
static xtensa_opcode xtensa_callx12_opcode;
static xtensa_opcode xtensa_const16_opcode;
static xtensa_opcode xtensa_entry_opcode;
+static xtensa_opcode xtensa_extui_opcode;
static xtensa_opcode xtensa_movi_opcode;
static xtensa_opcode xtensa_movi_n_opcode;
static xtensa_opcode xtensa_isync_opcode;
+static xtensa_opcode xtensa_j_opcode;
static xtensa_opcode xtensa_jx_opcode;
static xtensa_opcode xtensa_l32r_opcode;
static xtensa_opcode xtensa_loop_opcode;
static xtensa_opcode xtensa_retw_n_opcode;
static xtensa_opcode xtensa_rsr_lcount_opcode;
static xtensa_opcode xtensa_waiti_opcode;
+static int config_max_slots = 0;
\f
/* Command-line Options. */
-bfd_boolean use_literal_section = TRUE;
-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;
+bool use_literal_section = true;
+enum flix_level produce_flix = FLIX_ALL;
+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_density = OPTION_MD_BASE,
option_no_density,
+ option_flix,
+ option_no_generate_flix,
+ option_no_flix,
+
option_relax,
option_no_relax,
option_prefer_l32r,
option_prefer_const16,
- option_target_hardware
+ option_target_hardware,
+
+ option_trampolines,
+ option_no_trampolines,
+
+ 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 = "";
{ "density", no_argument, NULL, option_density },
{ "no-density", no_argument, NULL, option_no_density },
+ { "flix", no_argument, NULL, option_flix },
+ { "no-generate-flix", no_argument, NULL, option_no_generate_flix },
+ { "no-allow-flix", no_argument, NULL, option_no_flix },
+
/* Both "relax" and "generics" are deprecated and treated as equivalent
to the "transform" option. */
{ "relax", no_argument, NULL, option_relax },
{ "target-hardware", required_argument, NULL, option_target_hardware },
+ { "trampolines", no_argument, NULL, option_trampolines },
+ { "no-trampolines", no_argument, NULL, option_no_trampolines },
+
+ { "auto-litpools", no_argument, NULL, option_auto_litpools },
+ { "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 }
};
int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
{
switch (c)
{
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;
+ return 1;
+ case option_no_generate_flix:
+ produce_flix = FLIX_NO_GENERATE;
+ return 1;
+ case option_no_flix:
+ produce_flix = FLIX_NONE;
return 1;
case option_generics:
as_warn (_("--generics is deprecated; use --transform instead"));
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:
case option_target_hardware:
{
int earliest, latest = 0;
+ char *end;
if (*arg == 0 || *arg == '-')
as_fatal (_("invalid target hardware version"));
- earliest = strtol (arg, &arg, 0);
+ earliest = strtol (arg, &end, 0);
- if (*arg == 0)
+ if (*end == 0)
latest = earliest;
- else if (*arg == '-')
+ else if (*end == '-')
{
- if (*++arg == 0)
+ if (*++end == 0)
as_fatal (_("invalid target hardware version"));
- latest = strtol (arg, &arg, 0);
+ latest = strtol (end, &end, 0);
}
- if (*arg != 0)
+ if (*end != 0)
as_fatal (_("invalid target hardware version"));
xtensa_setup_hw_workarounds (earliest, latest);
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;
+ return 1;
+
+ case option_no_trampolines:
+ use_trampolines = false;
+ return 1;
+
+ case option_auto_litpools:
+ 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_litpool_limit = -1;
+ return 1;
+
+ case option_auto_litpool_limit:
+ {
+ int value = 0;
+ char *end;
+ if (auto_litpool_limit < 0)
+ as_fatal (_("no-auto-litpools is incompatible with auto-litpool-limit"));
+ if (*arg == 0 || *arg == '-')
+ as_fatal (_("invalid auto-litpool-limit argument"));
+ value = strtol (arg, &end, 10);
+ if (*end != 0)
+ as_fatal (_("invalid auto-litpool-limit argument"));
+ 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;
+ 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:
--[no-]target-align [Do not] try to align branch targets\n\
--[no-]longcalls [Do not] emit 32-bit call sequences\n\
--[no-]transform [Do not] transform instructions\n\
- --rename-section old=new Rename section 'old' to 'new'\n", stream);
+ --flix both allow hand-written and generate flix bundles\n\
+ --no-generate-flix allow hand-written but do not generate\n\
+ flix bundles\n\
+ --no-allow-flix neither allow hand-written nor generate\n\
+ flix bundles\n\
+ --rename-section old=new Rename section 'old' to 'new'\n\
+ --[no-]trampolines [Do not] generate trampolines (jumps to jumps)\n\
+ when jumps do not reach their targets\n\
+ --[no-]auto-litpools [Do not] automatically create literal pools\n\
+ --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\
+ --[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
sym_list *l;
if (!free_insn_labels)
- l = (sym_list *) xmalloc (sizeof (sym_list));
+ l = XNEW (sym_list);
else
{
l = free_insn_labels;
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;
{ "frame", s_ignore, 0 }, /* Formerly used for STABS debugging. */
{ "long", xtensa_elf_cons, 4 },
{ "word", xtensa_elf_cons, 4 },
+ { "4byte", xtensa_elf_cons, 4 },
{ "short", xtensa_elf_cons, 2 },
+ { "2byte", xtensa_elf_cons, 2 },
+ { "sleb128", xtensa_leb128, 1},
+ { "uleb128", xtensa_leb128, 0},
{ "begin", xtensa_begin_directive, 0 },
{ "end", xtensa_end_directive, 0 },
{ "literal", xtensa_literal_pseudo, 0 },
};
-static bfd_boolean
+static bool
use_transform (void)
{
/* After md_end, you should be checking frag by frag, rather
than state directives. */
- assert (!past_xtensa_end);
+ gas_assert (!past_xtensa_end);
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
instead. There is no target-align directive, so alignment is either
enabled for all frags or not done at all. */
- assert (!past_xtensa_end);
+ gas_assert (!past_xtensa_end);
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)
{
- char *file;
+ const char *file;
unsigned int line;
- state_stackS *stack = (state_stackS *) xmalloc (sizeof (state_stackS));
+ state_stackS *stack = XNEW (state_stackS);
- as_where (&file, &line);
+ file = as_where (&line);
stack->directive = directive;
stack->negated = negated;
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;
- char *directive_string;
+ 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;
insn_labels = NULL;
}
as_warn (_(".begin literal is deprecated; use .literal instead"));
- state = (emit_state *) xmalloc (sizeof (emit_state));
+ state = XNEW (emit_state);
xtensa_switch_to_literal_fragment (state);
directive_push (directive_literal, negated, state);
break;
/* Allocate the literal state for this section and push
onto the directive stack. */
- ls = xmalloc (sizeof (lit_state));
- assert (ls);
+ ls = XNEW (lit_state);
+ gas_assert (ls);
*ls = default_lit_sections;
directive_push (directive_literal_prefix, negated, 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;
md_flush_pending_output ();
- switch (end_directive)
+ switch ((int) end_directive)
{
- case (directiveE) XTENSA_UNDEFINED:
+ case XTENSA_UNDEFINED:
discard_rest_of_line ();
return;
- case directive_density:
+ case (int) directive_density:
as_warn (_(".end [no-]density is ignored"));
demand_empty_rest_of_line ();
break;
- case directive_absolute_literals:
+ case (int) directive_absolute_literals:
if (!absolute_literals_supported && !end_negated)
{
as_warn (_("Xtensa absolute literals option not supported; ignored"));
case directive_literal_prefix:
/* Restore the default collection sections from saved state. */
s = (lit_state *) state;
- assert (s);
+ gas_assert (s);
default_lit_sections = *s;
/* Free the state storage. */
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;
-
/* All literals are aligned to four-byte boundaries. */
frag_align (2, 0, 0);
record_alignment (now_seg, 2);
- c = get_symbol_end ();
+ c = get_symbol_name (&base_name);
/* Just after name is now '\0'. */
p = input_line_pointer;
*p = c;
- SKIP_WHITESPACE ();
+ SKIP_WHITESPACE_AFTER_NAME ();
if (*input_line_pointer != ',' && *input_line_pointer != ':')
{
xtensa_restore_emit_state (&state);
return;
}
- *p = 0;
+ *p = 0;
colon (base_name);
-
*p = c;
+
input_line_pointer++; /* skip ',' or ':' */
xtensa_elf_cons (4);
"abcdefghijklmnopqrstuvwxyz_/0123456789.$");
/* Get a null-terminated copy of the name. */
- name = xmalloc (len + 1);
- assert (name);
- strncpy (name, input_line_pointer, len);
- name[len] = 0;
+ name = xmemdup0 (input_line_pointer, len);
/* Skip the name in the input line. */
input_line_pointer += len;
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
+ || reloc == BFD_RELOC_XTENSA_TLS_CALL)
+ as_bad (_("invalid use of %s relocation"), reloc_howto->name);
else
{
char *p = frag_more ((int) nbytes);
xtensa_set_frag_assembly_state (frag_now);
fix_new_exp (frag_now, p - frag_now->fr_literal,
- nbytes, &exp, 0, reloc);
+ nbytes, &exp, reloc_howto->pc_relative, reloc);
}
}
else
- emit_expr (&exp, (unsigned int) nbytes);
+ {
+ xtensa_set_frag_assembly_state (frag_now);
+ emit_expr (&exp, (unsigned int) nbytes);
+ }
}
while (*input_line_pointer++ == ',');
demand_empty_rest_of_line ();
}
+static bool is_leb128_expr;
+
+static void
+xtensa_leb128 (int sign)
+{
+ is_leb128_expr = true;
+ s_leb128 (sign);
+ is_leb128_expr = false;
+}
+
\f
/* Parsing and Idiom Translation. */
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;
-
- for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++)
+ operatorT operator = O_illegal;
+ unsigned int i;
+
+ 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;
}
}
- 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)
+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;
}
}
+ if (is_literal)
+ {
+ if (reloc == BFD_RELOC_XTENSA_TLS_FUNC)
+ return BFD_RELOC_XTENSA_TLSDESC_FN;
+ else if (reloc == BFD_RELOC_XTENSA_TLS_ARG)
+ return BFD_RELOC_XTENSA_TLSDESC_ARG;
+ }
+
if (reloc == BFD_RELOC_UNUSED)
return BFD_RELOC_32;
{
bfd_reloc_code_real_type reloc;
segT t = expression (tok);
+
if (t == absolute_section
&& xtensa_operand_is_PCrelative (isa, opc, opnd) == 1)
{
- assert (tok->X_op == O_constant);
+ gas_assert (tok->X_op == O_constant);
tok->X_op = O_symbol;
tok->X_add_symbol = &abs_symbol;
}
&& ((reloc = xtensa_elf_suffix (&input_line_pointer, tok))
!= BFD_RELOC_NONE))
{
- if (reloc == BFD_RELOC_UNUSED)
+ switch (reloc)
{
- as_bad (_("unsupported relocation"));
- return;
- }
-
- if (tok->X_op == O_constant)
- {
- switch (reloc)
+ case BFD_RELOC_LO16:
+ if (tok->X_op == O_constant)
{
- case BFD_RELOC_LO16:
tok->X_add_number &= 0xffff;
return;
-
- case BFD_RELOC_HI16:
+ }
+ break;
+ case BFD_RELOC_HI16:
+ if (tok->X_op == O_constant)
+ {
tok->X_add_number = ((unsigned) tok->X_add_number) >> 16;
return;
-
- default:
- break;
}
+ break;
+ case BFD_RELOC_UNUSED:
+ as_bad (_("unsupported relocation"));
+ return;
+ case BFD_RELOC_32_PCREL:
+ as_bad (_("pcrel relocation not allowed in an instruction"));
+ return;
+ default:
+ break;
}
tok->X_op = map_suffix_reloc_to_operator (reloc);
}
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:
arg_end += 1;
arg_len = arg_end - input_line_pointer;
- arg = (char *) xmalloc ((saw_colon ? 1 : 0) + arg_len + 1);
+ arg = XNEWVEC (char, (saw_colon ? 1 : 0) + arg_len + 1);
args[num_args] = arg;
if (saw_colon)
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;
input_line_pointer++;
if (num_regs == 0)
goto err;
- assert (opnd_cnt > 0);
+ gas_assert (opnd_cnt > 0);
num_regs--;
opnd_rf = xtensa_operand_regfile (isa, opcode, last_opnd_cnt);
if (next_reg
as_warn (_("too many arguments"));
goto err;
}
- assert (opnd_cnt < MAX_INSN_ARGS);
+ gas_assert (opnd_cnt < MAX_INSN_ARGS);
expression_maybe_register (opcode, opnd_cnt, tok);
next_reg = tok->X_add_number + 1;
last_tok = tok;
last_opnd_cnt = opnd_cnt;
+ demand_empty_rest_of_line ();
do
{
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 = (char *) xmalloc (strlen (cnt_arg) + 6);
- sprintf (new_arg, "31-(%s)", cnt_arg);
+ new_arg = concat ("31-(", cnt_arg, ")", (char *) NULL);
free (cnt_arg);
*cnt_argp = new_arg;
static void
-xg_replace_opname (char **popname, char *newop)
+xg_replace_opname (char **popname, const char *newop)
{
free (*popname);
- *popname = (char *) xmalloc (strlen (newop) + 1);
- strcpy (*popname, newop);
+ *popname = xstrdup (newop);
}
/* Another special case for "WSR.INTSET".... */
if (is_write && !is_user && !strcasecmp ("interrupt", sr_name))
sr_name = "intset";
- new_opname = (char *) xmalloc (strlen (sr_name) + 6);
- sprintf (new_opname, "%s.%s", *popname, sr_name);
+ new_opname = concat (*popname, ".", sr_name, (char *) NULL);
free (*popname);
*popname = new_opname;
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);
static int
-xtensa_translate_zero_immed (char *old_op,
- char *new_op,
+xtensa_translate_zero_immed (const char *old_op,
+ const char *new_op,
char **popname,
int *pnum_args,
char **arg_strings)
offsetT val;
opname = *popname;
- assert (opname[0] != '_');
+ gas_assert (opname[0] != '_');
if (strcmp (opname, old_op) != 0)
return 0;
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;
}
if (xg_check_num_args (pnum_args, 2, opname, arg_strings))
return -1;
xg_replace_opname (popname, (has_underbar ? "_or" : "or"));
- arg_strings[2] = (char *) xmalloc (strlen (arg_strings[1]) + 1);
- strcpy (arg_strings[2], arg_strings[1]);
+ arg_strings[2] = xstrdup (arg_strings[1]);
*pnum_args = 3;
}
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))
}
/* Don't do anything special with NOPs inside FLIX instructions. They
- are handled elsewhere. Real NOP instructions are always available
+ are handled elsewhere. Real NOP instructions are always available
in configurations with FLIX, so this should never be an issue but
check for it anyway. */
if (!cur_vinsn.inside_bundle && xtensa_nop_opcode == XTENSA_UNDEFINED
if (xg_check_num_args (pnum_args, 0, opname, arg_strings))
return -1;
xg_replace_opname (popname, (has_underbar ? "_or" : "or"));
- arg_strings[0] = (char *) xmalloc (3);
- arg_strings[1] = (char *) xmalloc (3);
- arg_strings[2] = (char *) xmalloc (3);
- strcpy (arg_strings[0], "a1");
- strcpy (arg_strings[1], "a1");
- strcpy (arg_strings[2], "a1");
+ arg_strings[0] = xstrdup ("a1");
+ arg_strings[1] = xstrdup ("a1");
+ arg_strings[2] = xstrdup ("a1");
*pnum_args = 3;
}
return 0;
#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;
if (xtensa_operand_is_PCrelative (xtensa_default_isa, opcode, operand)
== 1)
as_bad_where ((char *) file, line,
- _("operand %d of '%s' has out of range value '%u'"),
+ _("operand %d of '%s' has out of range value '%u'"),
operand + 1,
xtensa_opcode_name (xtensa_default_isa, opcode),
value);
/* The routine xg_instruction_matches_option_term must return TRUE
when a given option term is true. The meaning of all of the option
- terms is given interpretation by this function. This is needed when
- an option depends on the state of a directive, but there are no such
- options in use right now. */
+ terms is given interpretation by this function. */
-static bfd_boolean
-xg_instruction_matches_option_term (TInsn *insn ATTRIBUTE_UNUSED,
- const ReqOrOption *option)
+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;
else
{
as_fatal (_("internal error: unknown option name '%s'"),
}
-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_CONSTANT:
/* The expression must be the constant. */
- assert (cond->op_num < insn->ntok);
+ gas_assert (cond->op_num < insn->ntok);
exp1 = &insn->tok[cond->op_num];
if (expr_is_const (exp1))
{
{
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:
- assert (cond->op_num < insn->ntok);
- assert (cond->op_data < insn->ntok);
+ gas_assert (cond->op_num < insn->ntok);
+ gas_assert (cond->op_data < insn->ntok);
exp1 = &insn->tok[cond->op_num];
exp2 = &insn->tok[cond->op_data];
{
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;
{
TransitionTable *table = xg_build_simplify_table (&transition_rule_cmp);
TransitionList *l;
- assert (insn->opcode < table->num_opcodes);
+ gas_assert (insn->opcode < table->num_opcodes);
/* Walk through all of the possible transitions. */
for (l = table->table[insn->opcode]; l != NULL; l = l->next)
\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;
TransitionRule *match = 0;
- assert (insn->insn_type == ITYPE_INSN);
- assert (insn->opcode < table->num_opcodes);
+ gas_assert (insn->insn_type == ITYPE_INSN);
+ gas_assert (insn->opcode < table->num_opcodes);
for (l = table->table[insn->opcode]; l != NULL; l = l->next)
{
<= 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;
}
TransitionList *l;
int max_size = xg_get_single_size (opcode);
- assert (opcode < table->num_opcodes);
+ gas_assert (opcode < table->num_opcodes);
for (l = table->table[opcode]; l != NULL; l = l->next)
{
build_list = rule->to_instr;
if (is_unique_insn_expansion (rule))
{
- assert (build_list->typ == INSTR_INSTR);
+ gas_assert (build_list->typ == INSTR_INSTR);
this_size = xg_get_max_insn_widen_size (build_list->opcode);
}
else
TransitionList *l;
int max_size = 0;
- assert (opcode < table->num_opcodes);
+ gas_assert (opcode < table->num_opcodes);
for (l = table->table[opcode]; l != NULL; l = l->next)
{
build_list = rule->to_instr;
if (is_unique_insn_expansion (rule))
{
- assert (build_list->typ == INSTR_INSTR);
+ gas_assert (build_list->typ == INSTR_INSTR);
this_size = xg_get_max_insn_widen_literal_size (build_list->opcode);
}
else
}
-static bfd_boolean
+static bool
xg_is_relaxable_insn (TInsn *insn, int lateral_steps)
{
int steps_taken = 0;
TransitionTable *table = xg_build_widen_table (&transition_rule_cmp);
TransitionList *l;
- assert (insn->insn_type == ITYPE_INSN);
- assert (insn->opcode < table->num_opcodes);
+ gas_assert (insn->insn_type == ITYPE_INSN);
+ gas_assert (insn->opcode < table->num_opcodes);
for (l = table->table[insn->opcode]; l != NULL; l = l->next)
{
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_uminus:
case O_subtract:
case O_pltrel:
- return TRUE;
+ case O_pcrel:
+ case O_tlsfunc:
+ case O_tlsarg:
+ case O_tpoff:
+ case O_dtpoff:
+ 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;
int i;
int n = insn->ntok;
- assert (insn->insn_type == ITYPE_INSN);
+ gas_assert (insn->insn_type == ITYPE_INSN);
for (i = 0; i < n; ++i)
{
- const expressionS *expr = &insn->tok[i];
+ const expressionS *exp = &insn->tok[i];
+
if (xtensa_operand_is_register (isa, insn->opcode, i) == 1)
continue;
- switch (expr->X_op)
+ switch (exp->X_op)
{
case O_register:
case O_constant:
- if (xg_check_operand (expr->X_add_number, insn->opcode, i))
- return FALSE;
+ if (xg_check_operand (exp->X_add_number, insn->opcode, i))
+ return false;
break;
default:
/* The symbol should have a fixup associated with it. */
- 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,
int i;
int n = insn->ntok;
- assert (insn->insn_type == ITYPE_INSN);
+ gas_assert (insn->insn_type == ITYPE_INSN);
for (i = 0; i < n; ++i)
{
- const expressionS *expr = &insn->tok[i];
+ const expressionS *exp = &insn->tok[i];
+
if (xtensa_operand_is_register (isa, insn->opcode, i) == 1)
continue;
- switch (expr->X_op)
+ switch (exp->X_op)
{
case O_register:
case O_constant:
- if (xg_check_operand (expr->X_add_number, insn->opcode, i))
- return FALSE;
+ if (xg_check_operand (exp->X_add_number, insn->opcode, i))
+ 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, then assume it won't reach. */
- if (S_IS_WEAK (expr->X_add_symbol))
- return FALSE;
-
- if (is_direct_call_opcode (insn->opcode)
- && ! pc_frag->tc_frag_data.use_longcalls)
+ /* If it is a weak symbol or a symbol in a different section,
+ it cannot be known to fit at assembly time. */
+ if (S_IS_WEAK (exp->X_add_symbol)
+ || S_GET_SEGMENT (exp->X_add_symbol) != pc_seg)
{
- /* If callee is undefined or in a different segment, be
- optimistic and assume it will be in range. */
- if (S_GET_SEGMENT (expr->X_add_symbol) != pc_seg)
- return TRUE;
+ /* For a direct call with --no-longcalls, be optimistic and
+ assume it will be in range. If the symbol is weak and
+ undefined, it may remain undefined at link-time, in which
+ case it will have a zero value and almost certainly be out
+ of range for a direct call; thus, relax for undefined weak
+ symbols even if longcalls is not enabled. */
+ if (is_direct_call_opcode (insn->opcode)
+ && ! pc_frag->tc_frag_data.use_longcalls
+ && (! S_IS_WEAK (exp->X_add_symbol)
+ || S_IS_DEFINED (exp->X_add_symbol)))
+ return true;
+
+ return false;
}
- /* Only references within a segment can be known to fit in the
- operands at assembly time. */
- if (S_GET_SEGMENT (expr->X_add_symbol) != pc_seg)
- return FALSE;
-
- symbolP = expr->X_add_symbol;
+ symbolP = exp->X_add_symbol;
sym_frag = symbol_get_frag (symbolP);
- target = S_GET_VALUE (symbolP) + expr->X_add_number;
+ target = S_GET_VALUE (symbolP) + exp->X_add_number;
pc = pc_frag->fr_address + pc_offset;
/* If frag has yet to be reached on this pass, assume it
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;
symbolS *sym;
tinsn_init (targ);
- targ->linenum = insn->linenum;
+ targ->debug_line = insn->debug_line;
+ targ->loc_directive_seen = insn->loc_directive_seen;
switch (bi->typ)
{
case INSTR_INSTR:
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)
{
int op_num = op->op_num;
int op_data = op->op_data;
- assert (op->op_num < MAX_INSN_ARGS);
+ gas_assert (op->op_num < MAX_INSN_ARGS);
if (targ->ntok <= op_num)
targ->ntok = op_num + 1;
set_expr_const (&targ->tok[op_num], op_data);
break;
case OP_OPERAND:
- assert (op_data < insn->ntok);
+ gas_assert (op_data < insn->ntok);
copy_expr (&targ->tok[op_num], &insn->tok[op_data]);
break;
+ case OP_FREEREG:
+ if (insn->extra_arg.X_op != O_register)
+ return false;
+ copy_expr (&targ->tok[op_num], &insn->extra_arg);
+ break;
case OP_LITERAL:
sym = get_special_literal_symbol ();
set_expr_symbol_offset (&targ->tok[op_num], sym, 0);
+ if (insn->tok[op_data].X_op == O_tlsfunc
+ || insn->tok[op_data].X_op == O_tlsarg)
+ copy_expr (&targ->extra_arg, &insn->tok[op_data]);
break;
case OP_LABEL:
sym = get_special_label_symbol ();
break;
case OP_OPERAND_HI16U:
case OP_OPERAND_LOW16U:
- assert (op_data < insn->ntok);
+ gas_assert (op_data < insn->ntok);
if (expr_is_const (&insn->tok[op_data]))
{
long val;
/* For const16 we can create relocations for these. */
if (targ->opcode == XTENSA_UNDEFINED
|| (targ->opcode != xtensa_const16_opcode))
- return FALSE;
- assert (op_data < insn->ntok);
+ 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]);
if (targ->tok[op_num].X_op == O_symbol)
else if (op->typ == OP_OPERAND_LOW16U)
targ->tok[op_num].X_op = O_lo16;
else
- return FALSE;
+ return false;
}
}
break;
OP_OPERAND_F32MINUS */
if (xg_has_userdef_op_fn (op->typ))
{
- assert (op_data < insn->ntok);
+ gas_assert (op_data < insn->ntok);
if (expr_is_const (&insn->tok[op_data]))
{
long val;
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;
}
- assert (0);
+ gas_assert (0);
break;
}
}
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;
int op_data = op->op_data;
- assert (op->op_num < MAX_INSN_ARGS);
+ gas_assert (op->op_num < MAX_INSN_ARGS);
if (targ->ntok <= op_num)
targ->ntok = op_num + 1;
switch (op->typ)
{
case OP_OPERAND:
- assert (op_data < insn->ntok);
+ 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:
case OP_CONSTANT:
case OP_LABEL:
default:
- assert (0);
+ gas_assert (0);
break;
}
}
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? */
- assert (op == NULL);
+ gas_assert (op == NULL);
break;
default:
- assert (0);
+ 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;
TransitionTable *table = xg_build_widen_table (&transition_rule_cmp);
TransitionList *l;
- assert (insn->insn_type == ITYPE_INSN);
- assert (insn->opcode < table->num_opcodes);
+ gas_assert (insn->insn_type == ITYPE_INSN);
+ gas_assert (insn->opcode < table->num_opcodes);
for (l = table->table[insn->opcode]; l != NULL; l = l->next)
{
/* 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++)
{
- TInsn *insn = &istack->insn[i];
+ TInsn *tinsn = &istack->insn[i];
- if (insn->insn_type == ITYPE_INSN
- && !tinsn_has_symbolic_operands (insn)
- && !xg_immeds_fit (insn))
+ if (tinsn->insn_type == ITYPE_INSN
+ && !tinsn_has_symbolic_operands (tinsn)
+ && !xg_immeds_fit (tinsn))
{
istack->ninsn = stack_size;
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
steps_taken++;
}
}
- return FALSE;
+ return false;
}
\f
/* Relax the assembly instruction at least "min_steps".
- Return the number of steps taken. */
+ Return the number of steps taken.
+
+ For relaxation to correctly terminate, every relaxation chain must
+ terminate in one of two ways:
+
+ 1. If the chain from one instruction to the next consists entirely of
+ single instructions, then the chain *must* handle all possible
+ immediates without failing. It must not ever fail because an
+ immediate is out of range. The MOVI.N -> MOVI -> L32R relaxation
+ chain is one example. L32R loads 32 bits, and there cannot be an
+ immediate larger than 32 bits, so it satisfies this condition.
+ Single instruction relaxation chains are as defined by
+ xg_is_single_relaxable_instruction.
+
+ 2. Otherwise, the chain must end in a multi-instruction expansion: e.g.,
+ BNEZ.N -> BNEZ -> BNEZ.W15 -> BENZ.N/J
+
+ Strictly speaking, in most cases you can violate condition 1 and be OK
+ -- in particular when the last two instructions have the same single
+ size. But nevertheless, you should guarantee the above two conditions.
+
+ We could fix this so that single-instruction expansions correctly
+ terminate when they can't handle the range, but the error messages are
+ worse, and it actually turns out that in every case but one (18-bit wide
+ branches), you need a multi-instruction expansion to get the full range
+ anyway. And because 18-bit branches are handled identically to 15-bit
+ branches, there isn't any point in changing it. */
static int
xg_assembly_relax (IStack *istack,
{
int steps_taken = 0;
- /* assert (has no symbolic operands)
- Some of its immeds don't fit.
- Try to build a relaxed version.
- This may go through a couple of stages
- of single instruction transformations before
- we get there. */
+ /* Some of its immeds don't fit. Try to build a relaxed version.
+ This may go through a couple of stages of single instruction
+ transformations before we get there. */
TInsn single_target;
TInsn current_insn;
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,
}
-static void
-xg_force_frag_space (int size)
-{
- /* This may have the side effect of creating a new fragment for the
- space to go into. I just do not like the name of the "frag"
- functions. */
- frag_grow (size);
-}
-
-
static void
xg_finish_frag (char *last_insn,
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
fragS *old_frag;
- xg_force_frag_space (max_growth);
-
+ frag_grow (max_growth);
old_frag = frag_now;
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);
xtensa_set_frag_assembly_state (frag_now);
/* Just to make sure that we did not split it up. */
- assert (old_frag->fr_next == frag_now);
+ gas_assert (old_frag->fr_next == frag_now);
}
/* 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_INSTR:
new_insn->insn_type = ITYPE_INSN;
new_insn->opcode = instr_spec->opcode;
- new_insn->is_specific_opcode = FALSE;
- new_insn->linenum = old_insn->linenum;
break;
case INSTR_LITERAL_DEF:
new_insn->insn_type = ITYPE_LITERAL;
new_insn->opcode = XTENSA_UNDEFINED;
- new_insn->is_specific_opcode = FALSE;
- new_insn->linenum = old_insn->linenum;
break;
case INSTR_LABEL_DEF:
- as_bad (_("INSTR_LABEL_DEF not supported yet"));
- break;
+ abort ();
}
+ new_insn->is_specific_opcode = false;
+ new_insn->debug_line = old_insn->debug_line;
+ new_insn->loc_directive_seen = old_insn->loc_directive_seen;
for (b_op = instr_spec->ops; b_op != NULL; b_op = b_op->next)
{
{
case OP_CONSTANT:
/* The expression must be the constant. */
- assert (b_op->op_num < MAX_INSN_ARGS);
+ gas_assert (b_op->op_num < MAX_INSN_ARGS);
exp = &new_insn->tok[b_op->op_num];
set_expr_const (exp, b_op->op_data);
break;
case OP_OPERAND:
- assert (b_op->op_num < MAX_INSN_ARGS);
- assert (b_op->op_data < (unsigned) old_insn->ntok);
+ gas_assert (b_op->op_num < MAX_INSN_ARGS);
+ gas_assert (b_op->op_data < (unsigned) old_insn->ntok);
src_exp = &old_insn->tok[b_op->op_data];
exp = &new_insn->tok[b_op->op_num];
copy_expr (exp, src_exp);
case OP_LITERAL:
case OP_LABEL:
as_bad (_("can't handle generation of literal/labels yet"));
- assert (0);
+ gas_assert (0);
default:
as_bad (_("can't handle undefined OP TYPE"));
- assert (0);
+ gas_assert (0);
}
}
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. */
- assert (insn_spec != NULL);
- assert (insn_spec->next == NULL);
+ 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
+ and related syntax issues have already been checked. */
+ if (orig_insn->opcode == xtensa_extui_opcode)
+ {
+ int shiftimm = orig_insn->tok[2].X_add_number;
+ int maskimm = orig_insn->tok[3].X_add_number;
+ if (shiftimm + maskimm > 32)
+ {
+ as_bad (_("immediate operands sum to greater than 32"));
+ return true;
+ }
+ }
/* If the instruction will definitely need to be relaxed, it is better
to expand it now for better scheduling. Decide whether to expand
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. */
{
sym_list *l;
- l = (sym_list *) xmalloc (sizeof (sym_list));
+ l = XNEW (sym_list);
l->sym = sym;
l->next = literal_syms;
literal_syms = l;
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;
+ bool pcrel = false;
char *p;
/* size = 4 for L32R. It could easily be larger when we move to
set_expr_symbol_offset (&saved_loc, frag_now->fr_symbol, frag_now_fix ());
- assert (insn->insn_type == ITYPE_LITERAL);
- assert (insn->ntok == 1); /* must be only one token here */
+ gas_assert (insn->insn_type == ITYPE_LITERAL);
+ gas_assert (insn->ntok == 1); /* must be only one token here */
xtensa_switch_to_literal_fragment (&state);
switch (emit_val->X_op)
{
+ case O_pcrel:
+ pcrel = true;
+ /* fall through */
case O_pltrel:
+ case O_tlsfunc:
+ case O_tlsarg:
+ case O_tpoff:
+ case O_dtpoff:
p = frag_more (litsize);
xtensa_set_frag_assembly_state (frag_now);
- reloc = map_operator_to_reloc (emit_val->X_op);
+ reloc = map_operator_to_reloc (emit_val->X_op, true);
if (emit_val->X_add_symbol)
emit_val->X_op = O_symbol;
else
emit_val->X_op = O_constant;
fix_new_exp (frag_now, p - frag_now->fr_literal,
- litsize, emit_val, 0, reloc);
+ litsize, emit_val, pcrel, reloc);
break;
default:
break;
}
- assert (frag_now->tc_frag_data.literal_frag == NULL);
+ gas_assert (frag_now->tc_frag_data.literal_frag == NULL);
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);
lit_sym = frag_now->fr_symbol;
offsetT litalign = 2; /* 2^2 = 4 */
fragS *lit_saved_frag;
- assert (size % 4 == 0);
+ gas_assert (size % 4 == 0);
xtensa_switch_to_literal_fragment (&state);
frag_align (litalign, 0, 0);
record_alignment (now_seg, litalign);
- xg_force_frag_space (size);
+ frag_grow (size);
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,
int slot,
- expressionS *expr,
+ expressionS *exp,
fragS *fragP,
offsetT offset)
{
}
else if (opcode == xtensa_const16_opcode)
{
- if (expr->X_op == O_lo16)
+ if (exp->X_op == O_lo16)
{
reloc = encode_reloc (slot);
- expr->X_op = O_symbol;
+ exp->X_op = O_symbol;
}
- else if (expr->X_op == O_hi16)
+ else if (exp->X_op == O_hi16)
{
reloc = encode_alt_reloc (slot);
- expr->X_op = O_symbol;
+ exp->X_op = O_symbol;
}
}
{
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
into the symbol table where the generic portions of the assembler
won't know what to do with them. */
- if (expr->X_op == O_lo16 || expr->X_op == O_hi16)
+ if (exp->X_op == O_lo16 || exp->X_op == O_hi16)
{
as_bad (_("invalid expression for operand %i of '%s'"),
opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
- 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 = fix_new_exp (fragP, offset, fmt_length, expr,
+ the_fix = fix_new_exp (fragP, offset, fmt_length, exp,
howto->pc_relative, reloc);
the_fix->fx_no_overflow = 1;
- the_fix->tc_fix_data.X_add_symbol = expr->X_add_symbol;
- the_fix->tc_fix_data.X_add_number = expr->X_add_number;
+ the_fix->tc_fix_data.X_add_symbol = exp->X_add_symbol;
+ the_fix->tc_fix_data.X_add_number = exp->X_add_number;
the_fix->tc_fix_data.slot = slot;
- return TRUE;
+ 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;
int i;
if (lit_sym == 0)
return;
- assert (insn->insn_type == ITYPE_INSN);
+ gas_assert (insn->insn_type == ITYPE_INSN);
for (i = 0; i < insn->ntok; i++)
if (insn->tok[i].X_add_symbol == sym)
insn->tok[i].X_add_symbol = lit_sym;
/* 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;
}
/* If an instruction is about to grow, return the longer size. */
if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP1
- || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP2)
- return 3;
+ || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP2
+ || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP3)
+ {
+ /* For most frags at RELAX_IMMED_STEPX, with X > 0, the first
+ instruction in the relaxed version is of length 3. (The case
+ where we have to pull the instruction out of a FLIX bundle
+ is handled conservatively above.) However, frags with opcodes
+ that are expanding to wide branches end up having formats that
+ are not determinable by the RELAX_IMMED_STEPX enumeration, and
+ we can't tell directly what format the relaxer picked. This
+ is a wart in the design of the relaxer that should someday be
+ fixed, but would require major changes, or at least should
+ be accompanied by major changes to make use of that data.
+
+ In any event, we can tell that we are expanding from a single-slot
+ format to a wider one with the logic below. */
+
+ int i;
+ int relaxed_size = fmt_size + fragP->tc_frag_data.text_expansion[0];
+
+ for (i = 0; i < xtensa_isa_num_formats (isa); i++)
+ {
+ if (relaxed_size == xtensa_format_length (isa, i))
+ return relaxed_size;
+ }
+
+ return 3;
+ }
if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
return 2 + fragP->tc_frag_data.text_expansion[0];
|| next_fragP->fr_subtype == RELAX_UNREACHABLE)))
next_fragP = next_fragP->fr_next;
- assert (next_fragP->fr_type == rs_machine_dependent
+ gas_assert (next_fragP->fr_type == rs_machine_dependent
&& (next_fragP->fr_subtype == RELAX_MAYBE_UNREACHABLE
|| next_fragP->fr_subtype == RELAX_UNREACHABLE));
|| new_target->fr_subtype == RELAX_DESIRE_ALIGN)))
new_target = new_target->fr_next;
- assert (new_target->fr_type == rs_machine_dependent
+ gas_assert (new_target->fr_type == rs_machine_dependent
&& (new_target->fr_subtype == RELAX_MAYBE_DESIRE_ALIGN
|| new_target->fr_subtype == RELAX_DESIRE_ALIGN));
}
}
-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;
}
+/* As specified in the relaxation table, when a loop instruction is
+ relaxed, there are 24 bytes between the loop instruction itself and
+ the first instruction in the loop. */
+
+#define RELAXED_LOOP_INSN_BYTES 24
+
static addressT
next_frag_pre_opcode_bytes (const fragS *fragp)
{
been relaxed. Note that we can assume that the LOOP
instruction is in slot 0 because loops aren't bundleable. */
if (next_fragp->tc_frag_data.slot_subtypes[0] > RELAX_IMMED)
- return get_expanded_loop_offset (next_opcode);
+ return get_expanded_loop_offset (next_opcode) + RELAXED_LOOP_INSN_BYTES;
return 0;
}
{
/* 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)
fixes into this frchain's fix list. */
pool_location = frag_now;
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);
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);
}
else
tinsn->opcode = xtensa_nop_opcode;
- assert (tinsn->opcode != XTENSA_UNDEFINED);
+ gas_assert (tinsn->opcode != XTENSA_UNDEFINED);
}
}
/* This is the OFFSET of the loop instruction in the expanded loop.
This MUST correspond directly to the specification of the loop
expansion. It will be validated on fragment conversion. */
- assert (opcode != XTENSA_UNDEFINED);
+ gas_assert (opcode != XTENSA_UNDEFINED);
if (opcode == xtensa_loop_opcode)
return 0;
if (opcode == xtensa_loopnez_opcode)
static fragS *
get_literal_pool_location (segT seg)
{
+ if (auto_litpools)
+ {
+ struct litpool_seg *lps = litpool_seg_list.next;
+ struct litpool_frag *lpf;
+ for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
+ ;
+ if (lps)
+ {
+ 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
"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;
+ return ((sec->flags & SEC_DEBUGGING) == 0
+ && strcmp (sec->name, ".eh_frame") != 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;
addressT frag_addr;
xtensa_format fmt;
- xtensa_insnbuf_from_chars
- (isa, insnbuf, (unsigned char *) frag->fr_literal, 0);
- fmt = xtensa_format_decode (isa, insnbuf);
- op_size = xtensa_format_length (isa, fmt);
- frag_addr = frag->fr_address % xtensa_fetch_width;
+ if (frag->fr_fix == 0)
+ frag = next_non_empty_frag (frag);
- if (frag_addr + op_size > xtensa_fetch_width)
- as_warn_where (frag->fr_file, frag->fr_line,
- _("unaligned loop: %d bytes at 0x%lx"),
- op_size, (long) frag->fr_address);
+ if (frag)
+ {
+ xtensa_insnbuf_from_chars
+ (isa, insnbuf, (unsigned char *) frag->fr_literal, 0);
+ fmt = xtensa_format_decode (isa, insnbuf);
+ op_size = xtensa_format_length (isa, fmt);
+ frag_addr = frag->fr_address % xtensa_fetch_width;
+
+ if (frag_addr + op_size > xtensa_fetch_width)
+ as_warn_where (frag->fr_file, frag->fr_line,
+ _("unaligned loop: %d bytes at 0x%lx"),
+ op_size, (long) frag->fr_address);
+ }
}
frag = frag->fr_next;
}
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;
- (void) decode_reloc (fixP->fx_r_type, &slot, &alt_reloc);
- if (alt_reloc)
+ if (decode_reloc (fixP->fx_r_type, &slot, &alt_reloc)
+ || alt_reloc)
as_fatal (_("unexpected fix"));
if (!insnbuf)
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
segT current_section = now_seg;
int current_subsec = now_subseg;
xtensa_isa isa;
+ int i;
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));
subseg_set (current_section, current_subsec);
- xg_init_vinsn (&cur_vinsn);
-
xtensa_addi_opcode = xtensa_opcode_lookup (isa, "addi");
xtensa_addmi_opcode = xtensa_opcode_lookup (isa, "addmi");
xtensa_call0_opcode = xtensa_opcode_lookup (isa, "call0");
xtensa_callx12_opcode = xtensa_opcode_lookup (isa, "callx12");
xtensa_const16_opcode = xtensa_opcode_lookup (isa, "const16");
xtensa_entry_opcode = xtensa_opcode_lookup (isa, "entry");
+ xtensa_extui_opcode = xtensa_opcode_lookup (isa, "extui");
xtensa_movi_opcode = xtensa_opcode_lookup (isa, "movi");
xtensa_movi_n_opcode = xtensa_opcode_lookup (isa, "movi.n");
xtensa_isync_opcode = xtensa_opcode_lookup (isa, "isync");
+ xtensa_j_opcode = xtensa_opcode_lookup (isa, "j");
xtensa_jx_opcode = xtensa_opcode_lookup (isa, "jx");
xtensa_l32r_opcode = xtensa_opcode_lookup (isa, "l32r");
xtensa_loop_opcode = xtensa_opcode_lookup (isa, "loop");
xtensa_rsr_lcount_opcode = xtensa_opcode_lookup (isa, "rsr.lcount");
xtensa_waiti_opcode = xtensa_opcode_lookup (isa, "waiti");
+ for (i = 0; i < xtensa_isa_num_formats (isa); i++)
+ {
+ int format_slots = xtensa_format_num_slots (isa, i);
+ if (format_slots > config_max_slots)
+ config_max_slots = format_slots;
+ }
+
+ xg_init_vinsn (&cur_vinsn);
+
+ xtensa_num_pipe_stages = xtensa_isa_num_pipe_stages (isa);
+
init_op_placement_info_table ();
/* 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 ();
}
/* No target aligning in the absolute section. */
if (now_seg != absolute_section
- && do_align_targets ()
&& !is_unaligned_label (sym)
&& !generating_literals)
{
xtensa_set_frag_assembly_state (frag_now);
- frag_var (rs_machine_dependent,
- 0, (int) freq,
- RELAX_DESIRE_ALIGN_IF_TARGET,
- frag_now->fr_symbol, frag_now->fr_offset, NULL);
+ if (do_align_targets ())
+ frag_var (rs_machine_dependent, 0, (int) freq,
+ RELAX_DESIRE_ALIGN_IF_TARGET, frag_now->fr_symbol,
+ frag_now->fr_offset, NULL);
+ else
+ frag_var (rs_fill, 0, 0, frag_now->fr_subtype,
+ frag_now->fr_symbol, frag_now->fr_offset, NULL);
xtensa_set_frag_assembly_state (frag_now);
xtensa_move_labels (frag_now, 0);
}
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 ();
}
md_assemble (char *str)
{
xtensa_isa isa = xtensa_default_isa;
- char *opname, *file_name;
+ 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. */
/* Split off the opcode. */
opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_/0123456789.");
- opname = xmalloc (opnamelen + 1);
- memcpy (opname, str, opnamelen);
- opname[opnamelen] = '\0';
+ opname = xstrndup (str, opnamelen);
num_args = tokenize_arguments (arg_strings, str + opnamelen);
if (num_args == -1)
/* Check for an underbar prefix. */
if (*opname == '_')
{
- has_underbar = TRUE;
+ has_underbar = true;
opname += 1;
}
orig_insn.insn_type = ITYPE_INSN;
orig_insn.ntok = 0;
orig_insn.is_specific_opcode = (has_underbar || !use_transform ());
-
orig_insn.opcode = xtensa_opcode_lookup (isa, opname);
+
+ /* 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)
+ {
+ unsigned long window_size;
+ char *suffix;
+
+ window_size = strtoul (opname + 5, &suffix, 10);
+ if (suffix != opname + 5
+ && (window_size == 0
+ || window_size == 4
+ || window_size == 8
+ || window_size == 12)
+ && strcasecmp (suffix, ".tls") == 0)
+ {
+ switch (window_size)
+ {
+ case 0: orig_insn.opcode = xtensa_callx0_opcode; break;
+ case 4: orig_insn.opcode = xtensa_callx4_opcode; break;
+ case 8: orig_insn.opcode = xtensa_callx8_opcode; break;
+ case 12: orig_insn.opcode = xtensa_callx12_opcode; break;
+ }
+
+ if (num_args != 2)
+ as_bad (_("wrong number of operands for '%s'"), opname);
+ else
+ {
+ bfd_reloc_code_real_type reloc;
+ char *old_input_line_pointer;
+ expressionS *tok = &orig_insn.extra_arg;
+
+ old_input_line_pointer = input_line_pointer;
+ input_line_pointer = arg_strings[num_args - 1];
+
+ expression (tok);
+ if (tok->X_op == O_symbol
+ && ((reloc = xtensa_elf_suffix (&input_line_pointer, tok))
+ == BFD_RELOC_XTENSA_TLS_CALL))
+ tok->X_op = map_suffix_reloc_to_operator (reloc);
+ else
+ as_bad (_("bad relocation expression for '%s'"), opname);
+
+ input_line_pointer = old_input_line_pointer;
+ num_args -= 1;
+ }
+ }
+ }
+
+ /* Special case: Check for "j.l" pseudo op. */
+ if (orig_insn.opcode == XTENSA_UNDEFINED
+ && strncasecmp (opname, "j.l", 3) == 0)
+ {
+ if (num_args != 2)
+ as_bad (_("wrong number of operands for '%s'"), opname);
+ else
+ {
+ char *old_input_line_pointer;
+ expressionS *tok = &orig_insn.extra_arg;
+
+ old_input_line_pointer = input_line_pointer;
+ input_line_pointer = arg_strings[num_args - 1];
+
+ expression_maybe_register (xtensa_jx_opcode, 0, tok);
+ input_line_pointer = old_input_line_pointer;
+
+ num_args -= 1;
+ orig_insn.opcode = xtensa_j_opcode;
+ }
+ }
+
if (orig_insn.opcode == XTENSA_UNDEFINED)
{
xtensa_format fmt = xtensa_format_lookup (isa, opname);
return;
}
- /* A FLIX bundle may be spread across multiple input lines. We want to
- report the first such line in the debug information. Record the line
- number for each TInsn (assume the file name doesn't change), so the
- first line can be found later. */
- as_where (&file_name, &orig_insn.linenum);
+ /* Record the line number for each TInsn, because a FLIX bundle may be
+ spread across multiple input lines and individual instructions may be
+ moved around in some cases. */
+ orig_insn.loc_directive_seen = dwarf2_loc_directive_seen;
+ dwarf2_where (&orig_insn.debug_line);
+ dwarf2_consume_line_info ();
xg_add_branch_and_loop_targets (&orig_insn);
/* We've just emitted a new instruction so clear the list of labels. */
xtensa_clear_insn_labels ();
+
+ xtensa_check_frag_count ();
}
&& ! fragP->tc_frag_data.is_literal
&& (fragP->fr_type == rs_align
|| fragP->fr_type == rs_align_code)
- && fragP->fr_address + fragP->fr_fix > 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;
+ if (fixP->fx_r_type == BFD_RELOC_32_PCREL)
+ return addr;
+
if (!insnbuf)
{
insnbuf = xtensa_insnbuf_alloc (isa);
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)
{
- /* An offset is not allowed in combination with the difference of two
- symbols, but that cannot be easily detected after a local symbol
- has been adjusted to a (section+offset) form. Return 0 so that such
- an fix will not be adjusted. */
- if (fixP->fx_subsy && fixP->fx_addsy && fixP->fx_offset
- && relaxable_section (S_GET_SEGMENT (fixP->fx_subsy)))
- return 0;
-
/* We need the symbol name for the VTABLE entries. */
if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
}
+/* tc_symbol_new_hook */
+
+symbolS *expr_symbols = NULL;
+
+void
+xtensa_symbol_new_hook (symbolS *sym)
+{
+ if (is_leb128_expr && S_GET_SEGMENT (sym) == expr_section)
+ {
+ symbol_get_tc (sym)->next_expr_symbol = expr_symbols;
+ expr_symbols = sym;
+ }
+}
+
+
void
md_apply_fix (fixS *fixP, valueT *valP, segT seg)
{
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_32_PCREL:
case BFD_RELOC_32:
case BFD_RELOC_16:
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:
break;
}
- /* An offset is only allowed when it results from adjusting a
- local symbol into a section-relative offset. If the offset
- came from the original expression, tc_fix_adjustable will have
- prevented the fix from being converted to a section-relative
- form so that we can flag the error here. */
- if (fixP->fx_offset != 0 && !symbol_section_p (fixP->fx_addsy))
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("cannot represent subtraction with an offset"));
-
val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
- S_GET_VALUE (fixP->fx_subsy));
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:
fixP->fx_no_overflow = 0; /* Use the standard overflow check. */
break;
+ case BFD_RELOC_XTENSA_TLSDESC_FN:
+ case BFD_RELOC_XTENSA_TLSDESC_ARG:
+ case BFD_RELOC_XTENSA_TLS_TPOFF:
+ case BFD_RELOC_XTENSA_TLS_DTPOFF:
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ md_number_to_chars (fixpos, 0, fixP->fx_size);
+ fixP->fx_no_overflow = 0; /* Use the standard overflow check. */
+ break;
+
case BFD_RELOC_XTENSA_SLOT0_OP:
case BFD_RELOC_XTENSA_SLOT1_OP:
case BFD_RELOC_XTENSA_SLOT2_OP:
by the linker, and it makes the object file disassembly
readable when all branch targets are encoded in relocations. */
- assert (fixP->fx_addsy);
+ gas_assert (fixP->fx_addsy);
if (S_GET_SEGMENT (fixP->fx_addsy) == seg
&& !S_FORCE_RELOC (fixP->fx_addsy, 1))
{
break;
case BFD_RELOC_XTENSA_ASM_EXPAND:
+ case BFD_RELOC_XTENSA_TLS_FUNC:
+ case BFD_RELOC_XTENSA_TLS_ARG:
+ case BFD_RELOC_XTENSA_TLS_CALL:
case BFD_RELOC_XTENSA_SLOT0_ALT:
case BFD_RELOC_XTENSA_SLOT1_ALT:
case BFD_RELOC_XTENSA_SLOT2_ALT:
}
-char *
+const char *
md_atof (int type, char *litP, int *sizeP)
{
- int prec;
- LITTLENUM_TYPE words[4];
- char *t;
- int i;
-
- switch (type)
- {
- case 'f':
- prec = 2;
- break;
-
- case 'd':
- prec = 4;
- break;
-
- default:
- *sizeP = 0;
- return "bad call to md_atof";
- }
-
- t = atof_ieee (input_line_pointer, type, words);
- if (t)
- input_line_pointer = t;
-
- *sizeP = prec * 2;
-
- for (i = prec - 1; i >= 0; i--)
- {
- int idx = i;
- if (target_big_endian)
- idx = (prec - 1 - i);
-
- md_number_to_chars (litP, (valueT) words[idx], 2);
- litP += 2;
- }
-
- return NULL;
+ return ieee_md_atof (type, litP, sizeP, target_big_endian);
}
{
arelent *reloc;
- reloc = (arelent *) xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ reloc = XNEW (arelent);
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
/* Make sure none of our internal relocations make it this far.
They'd better have been fully resolved by this point. */
- assert ((int) fixp->fx_r_type > 0);
+ gas_assert ((int) fixp->fx_r_type > 0);
reloc->addend = fixp->fx_offset;
}
if (!fixp->fx_pcrel != !reloc->howto->pc_relative)
- as_fatal (_("internal error? cannot generate `%s' relocation"),
+ as_fatal (_("internal error; cannot generate `%s' relocation"),
bfd_get_reloc_code_name (fixp->fx_r_type));
return reloc;
opcode_funcUnit_use_stage_func ousf)
{
int i;
- resource_table *rt = (resource_table *) xmalloc (sizeof (resource_table));
+ resource_table *rt = XNEW (resource_table);
rt->data = data;
rt->cycles = cycles;
rt->allocated_cycles = cycles;
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;
}
old_cycles = rt->allocated_cycles;
rt->allocated_cycles = cycles;
- rt->units = xrealloc (rt->units,
- rt->allocated_cycles * sizeof (unsigned char *));
+ rt->units = XRESIZEVEC (unsigned char *, rt->units, rt->allocated_cycles);
for (i = 0; i < old_cycles; i++)
- rt->units[i] = xrealloc (rt->units[i],
- rt->num_units * sizeof (unsigned char));
+ 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;
}
{
xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i);
int stage = (rt->opcode_unit_stage) (rt->data, opcode, i);
- assert (rt->units[stage + cycle][unit] > 0);
+ gas_assert (rt->units[stage + cycle][unit] > 0);
rt->units[stage + cycle][unit]--;
}
}
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)
{
xtensa_isa isa = xtensa_default_isa;
rt = new_resource_table
- (isa, xtensa_isa_num_pipe_stages (isa),
+ (isa, xtensa_num_pipe_stages,
xtensa_isa_num_funcUnits (isa),
(unit_num_copies_func) xtensa_funcUnit_num_copies,
(opcode_num_units_func) xtensa_opcode_num_funcUnit_uses,
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;
- char *file_name;
- unsigned line;
+ int slots;
if (find_vinsn_conflicts (vinsn))
{
if (vinsn->format == XTENSA_UNDEFINED)
vinsn->format = xg_find_narrowest_format (vinsn);
+ 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."));
+ xg_clear_vinsn (vinsn);
+ return;
+ }
+
if (vinsn->format == XTENSA_UNDEFINED)
{
- as_where (&file_name, &line);
- as_bad_where (file_name, line,
- _("couldn't find a valid instruction format"));
+ as_bad (_("couldn't find a valid instruction format"));
fprintf (stderr, _(" ops were: "));
for (i = 0; i < vinsn->num_slots; i++)
fprintf (stderr, _(" %s;"),
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;
}
if (resources_conflict (vinsn))
{
- as_where (&file_name, &line);
- as_bad_where (file_name, line, _("illegal resource usage in bundle"));
+ as_bad (_("illegal resource usage in bundle"));
fprintf (stderr, " ops were: ");
for (i = 0; i < vinsn->num_slots; i++)
fprintf (stderr, " %s;",
{
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;
}
TInsn *insn = &slotstack.insn[j];
if (insn->insn_type == ITYPE_LITERAL)
{
- assert (lit_sym == NULL);
+ gas_assert (lit_sym == NULL);
lit_sym = xg_assemble_literal (insn);
}
else
{
- assert (insn->insn_type == ITYPE_INSN);
+ gas_assert (insn->insn_type == ITYPE_INSN);
if (lit_sym)
xg_resolve_literals (insn, lit_sym);
if (j != slotstack.ninsn - 1)
/* Now check resource conflicts on the modified bundle. */
if (resources_conflict (vinsn))
{
- as_where (&file_name, &line);
- as_bad_where (file_name, line, _("illegal resource usage in bundle"));
+ as_bad (_("illegal resource usage in bundle"));
fprintf (stderr, " ops were: ");
for (i = 0; i < vinsn->num_slots; i++)
fprintf (stderr, " %s;",
xg_assemble_vliw_tokens (vinsn);
xg_clear_vinsn (vinsn);
+
+ xtensa_check_frag_count ();
}
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;
- assert (!past_xtensa_end);
+ gas_assert (!past_xtensa_end);
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++)
{
xtensa_state t1_so = xtensa_stateOperand_state (isa, t1->opcode, i);
t1_inout = xtensa_stateOperand_inout (isa, t1->opcode, i);
- if (t1_so != t2_so)
+ if (t1_so != t2_so || xtensa_state_is_shared_or (isa, t1_so) == 1)
continue;
if (t2_inout == 'i' && (t1_inout == 'm' || t1_inout == 'o'))
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';
xtensa_isa isa = xtensa_default_isa;
xtensa_format format;
- vliw_insn v_copy = *vinsn;
xtensa_opcode nop_opcode = xtensa_nop_opcode;
if (vinsn->num_slots == 1)
for (format = 0; format < xtensa_isa_num_formats (isa); format++)
{
- v_copy = *vinsn;
+ vliw_insn v_copy;
+ xg_copy_vinsn (&v_copy, vinsn);
if (xtensa_format_num_slots (isa, format) == v_copy.num_slots)
{
int slot;
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))
{
}
if (fit == v_copy.num_slots)
{
- *vinsn = v_copy;
+ xg_copy_vinsn (vinsn, &v_copy);
xtensa_format_encode (isa, format, vinsn->insnbuf);
vinsn->format = format;
break;
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;
}
}
}
int slot, chosen_slot;
vinsn->format = xg_get_single_format (tinsn->opcode);
- assert (vinsn->format != XTENSA_UNDEFINED);
+ gas_assert (vinsn->format != XTENSA_UNDEFINED);
vinsn->num_slots = xtensa_format_num_slots (isa, vinsn->format);
chosen_slot = xg_get_single_slot (tinsn->opcode);
}
-static bfd_boolean
+static bool
emit_single_op (TInsn *orig_insn)
{
int i;
|| orig_insn->opcode == xtensa_movi_n_opcode)
&& !cur_vinsn.inside_bundle
&& (orig_insn->tok[1].X_op == O_symbol
- || orig_insn->tok[1].X_op == O_pltrel)
+ || orig_insn->tok[1].X_op == O_pltrel
+ || orig_insn->tok[1].X_op == O_tlsfunc
+ || orig_insn->tok[1].X_op == O_tlsarg
+ || orig_insn->tok[1].X_op == O_tpoff
+ || orig_insn->tok[1].X_op == O_dtpoff)
&& !orig_insn->is_specific_opcode && use_transform ())
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++)
{
switch (insn->insn_type)
{
case ITYPE_LITERAL:
- assert (lit_sym == NULL);
+ gas_assert (lit_sym == NULL);
lit_sym = xg_assemble_literal (insn);
break;
case ITYPE_LABEL:
{
static int relaxed_sym_idx = 0;
- char *label = xmalloc (strlen (FAKE_LABEL_NAME) + 12);
+ char *label = XNEWVEC (char, strlen (FAKE_LABEL_NAME) + 12);
sprintf (label, "%s_rl_%x", FAKE_LABEL_NAME, relaxed_sym_idx++);
colon (label);
- assert (label_sym == NULL);
+ gas_assert (label_sym == NULL);
label_sym = symbol_find_or_make (label);
- assert (label_sym);
+ gas_assert (label_sym);
free (label);
}
break;
}
break;
default:
- assert (0);
+ gas_assert (0);
break;
}
}
- return FALSE;
+ return false;
}
int slot;
int total_expansion = 0;
- for (slot = 0; slot < MAX_SLOTS; slot++)
+ for (slot = 0; slot < config_max_slots; slot++)
total_expansion += fragP->tc_frag_data.text_expansion[slot];
return total_expansion;
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 i;
int insn_size;
int extra_space;
char *f = NULL;
int slot;
- unsigned current_line, best_linenum;
- char *current_file;
+ struct dwarf2_line_info debug_line;
+ bool loc_directive_seen = false;
+ TInsn *tinsn;
- best_linenum = UINT_MAX;
+ memset (&debug_line, 0, sizeof (struct dwarf2_line_info));
if (generating_literals)
{
if (frag_now_fix () != 0
&& (! frag_now->tc_frag_data.is_insn
|| (vinsn_has_specific_opcodes (vinsn) && use_transform ())
- || !use_transform () != frag_now->tc_frag_data.is_no_transform
+ || (!use_transform ()) != frag_now->tc_frag_data.is_no_transform
|| (directive_state[directive_longcalls]
!= frag_now->tc_frag_data.use_longcalls)
|| (directive_state[directive_absolute_literals]
&& 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,
xtensa_set_frag_assembly_state (frag_now);
}
- for (i = 0; i < vinsn->num_slots; i++)
+ for (slot = 0; slot < vinsn->num_slots; slot++)
{
+ tinsn = &vinsn->slots[slot];
+
/* See if the instruction implies an aligned section. */
- if (xtensa_opcode_is_loop (isa, vinsn->slots[i].opcode) == 1)
+ if (xtensa_opcode_is_loop (isa, tinsn->opcode) == 1)
record_alignment (now_seg, 2);
- /* Also determine the best line number for debug info. */
- best_linenum = vinsn->slots[i].linenum < best_linenum
- ? vinsn->slots[i].linenum : best_linenum;
+ /* Determine the best line number for debug info. */
+ if ((tinsn->loc_directive_seen || !loc_directive_seen)
+ && (tinsn->debug_line.filenum != debug_line.filenum
+ || tinsn->debug_line.line < debug_line.line
+ || tinsn->debug_line.column < debug_line.column))
+ debug_line = tinsn->debug_line;
+ if (tinsn->loc_directive_seen)
+ loc_directive_seen = true;
}
/* Special cases for instructions that force an alignment... */
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;
xtensa_insnbuf_to_chars (isa, vinsn->insnbuf, (unsigned char *) f, 0);
- /* Temporarily set the logical line number to the one we want to appear
- in the debug information. */
- as_where (¤t_file, ¤t_line);
- new_logical_line (current_file, best_linenum);
- dwarf2_emit_insn (insn_size + extra_space);
- new_logical_line (current_file, current_line);
+ if (debug_type == DEBUG_DWARF2 || loc_directive_seen)
+ dwarf2_gen_line_info (frag_now_fix () - (insn_size + extra_space),
+ &debug_line);
for (slot = 0; slot < vinsn->num_slots; slot++)
{
- TInsn *tinsn = &vinsn->slots[slot];
+ tinsn = &vinsn->slots[slot];
frag_now->tc_frag_data.slot_subtypes[slot] = tinsn->subtype;
frag_now->tc_frag_data.slot_symbols[slot] = tinsn->symbol;
frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset;
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]
+ = 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)
- assert (vinsn->num_slots == 1);
+ 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);
{
if (is_jump)
{
- assert (finish_frag);
+ gas_assert (finish_frag);
frag_var (rs_machine_dependent,
- UNREACHABLE_MAX_WIDTH, UNREACHABLE_MAX_WIDTH,
+ xtensa_fetch_width, xtensa_fetch_width,
RELAX_UNREACHABLE,
frag_now->fr_symbol, frag_now->fr_offset, NULL);
xtensa_set_frag_assembly_state (frag_now);
+ xtensa_maybe_create_trampoline_frag ();
+ /* Always create one here. */
+ xtensa_maybe_create_literal_pool_frag (true, false);
}
else if (is_branch && do_align_targets ())
{
- assert (finish_frag);
+ gas_assert (finish_frag);
frag_var (rs_machine_dependent,
- UNREACHABLE_MAX_WIDTH, UNREACHABLE_MAX_WIDTH,
+ xtensa_fetch_width, xtensa_fetch_width,
RELAX_MAYBE_UNREACHABLE,
frag_now->fr_symbol, frag_now->fr_offset, NULL);
xtensa_set_frag_assembly_state (frag_now);
&& 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);
static void xtensa_fix_target_frags (void);
static void xtensa_mark_narrow_branches (void);
static void xtensa_mark_zcl_first_insns (void);
+static void xtensa_mark_difference_of_two_symbols (void);
static void xtensa_fix_a0_b_retw_frags (void);
static void xtensa_fix_b_j_loop_end_frags (void);
static void xtensa_fix_close_loop_end_frags (void);
directive_balance ();
xtensa_flush_pending_output ();
- past_xtensa_end = TRUE;
+ past_xtensa_end = true;
xtensa_move_literals ();
xtensa_sanity_check ();
xtensa_add_config_info ();
+
+ 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_chain_index
+{
+ 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;
+ /* 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;
+
+
+static void
+xtensa_maybe_create_trampoline_frag (void)
+{
+ if (!use_trampolines)
+ return;
+
+ /* We create an area for possible trampolines every 10 unreachable frags.
+ These are preferred over the ones not preceded by an unreachable frag,
+ because we don't have to jump around them. This function is called after
+ each RELAX_UNREACHABLE frag is created. */
+
+ if (++unreachable_count > 10)
+ {
+ xtensa_create_trampoline_frag (false);
+ clear_frag_count ();
+ unreachable_count = 0;
+ }
+}
+
+static void
+xtensa_check_frag_count (void)
+{
+ if (!use_trampolines || frag_now->tc_frag_data.is_no_transform)
+ return;
+
+ /* We create an area for possible trampolines every 8000 frags or so. This
+ is an estimate based on the max range of a "j" insn (+/-128K) divided
+ by a typical frag byte count (16), minus a few for safety. This function
+ is called after each source line is processed. */
+
+ if (get_frag_count () > 8000)
+ {
+ 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);
+}
+
+static xtensa_insnbuf trampoline_buf = NULL;
+static xtensa_insnbuf trampoline_slotbuf = NULL;
+
+static xtensa_insnbuf litpool_buf = NULL;
+static xtensa_insnbuf litpool_slotbuf = 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 (bool needs_jump_around)
+{
+ /* Emit a frag where we can place intermediate jump instructions,
+ in case we need to jump farther than 128K bytes.
+ Each jump instruction takes three bytes.
+ We allocate enough for 1000 trampolines in each frag.
+ If that's not enough, oh well. */
+
+ struct trampoline_seg *ts = find_trampoline_seg (now_seg);
+ char *varP;
+ fragS *fragP;
+ int size = TRAMPOLINE_FRAG_SIZE;
+
+ if (ts == NULL)
+ {
+ ts = XCNEW(struct trampoline_seg);
+ ts->next = trampoline_seg_list.next;
+ trampoline_seg_list.next = ts;
+ ts->seg = now_seg;
+ }
+
+ frag_wane (frag_now);
+ frag_new (0);
+ xtensa_set_frag_assembly_state (frag_now);
+ varP = frag_var (rs_machine_dependent, size, size, RELAX_TRAMPOLINE, NULL, 0, NULL);
+ fragP = (fragS *)(varP - SIZEOF_STRUCT_FRAG);
+ if (trampoline_buf == NULL)
+ {
+ trampoline_buf = xtensa_insnbuf_alloc (xtensa_default_isa);
+ trampoline_slotbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
+ }
+ 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 int xg_order_trampoline_chain_entry (const void *a, const void *b)
+{
+ const struct trampoline_chain_entry *pa = a;
+ const struct trampoline_chain_entry *pb = b;
+
+ if (pa->sym != pb->sym)
+ {
+ 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;
+}
+
+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);
+
+void
+dump_trampolines (void)
+{
+ struct trampoline_seg *ts = trampoline_seg_list.next;
+
+ for ( ; ts; ts = ts->next)
+ {
+ size_t i;
+ asection *seg = ts->seg;
+
+ if (seg == NULL)
+ continue;
+ fprintf(stderr, "SECTION %s\n", seg->name);
+
+ for (i = 0; i < ts->index.n_entries; ++i)
+ {
+ fragS *tf = ts->index.entry[i];
+
+ fprintf(stderr, " 0x%08x: fix=%d, jump_around=%s\n",
+ (int)tf->fr_address, (int)tf->fr_fix,
+ tf->tc_frag_data.needs_jump_around ? "T" : "F");
+ }
+ }
+}
+
+static void dump_litpools (void) __attribute__ ((unused));
+
+static void
+dump_litpools (void)
+{
+ struct litpool_seg *lps = litpool_seg_list.next;
+ struct litpool_frag *lpf;
+
+ for ( ; lps ; lps = lps->next )
+ {
+ printf("litpool seg %s\n", lps->seg->name);
+ for ( lpf = lps->frag_list.next; lpf->fragP; lpf = lpf->next )
+ {
+ fragS *litfrag = lpf->fragP->fr_next;
+ int count = 0;
+ while (litfrag && litfrag->fr_subtype != RELAX_LITERAL_POOL_END)
+ {
+ if (litfrag->fr_fix == 4)
+ count++;
+ litfrag = litfrag->fr_next;
+ }
+ printf(" %ld <%d:%d> (%d) [%d]: ",
+ lpf->addr, lpf->priority, lpf->original_priority,
+ lpf->fragP->fr_line, count);
+ /* dump_frag(lpf->fragP); */
+ }
+ }
+}
+
+static void
+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;
+ bool needed = false;
+
+ if (use_literal_section || !auto_litpools)
+ return;
+
+ for ( ; lps ; lps = lps->next )
+ {
+ if (lps->seg == now_seg)
+ break;
+ }
+
+ if (lps == NULL)
+ {
+ 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 (create)
+ {
+ if (only_if_needed)
+ {
+ if (past_xtensa_end || !use_transform() ||
+ frag_now->tc_frag_data.is_no_transform)
+ {
+ return;
+ }
+ if (auto_litpool_limit <= 0)
+ {
+ /* Don't create a litpool based only on frag count. */
+ return;
+ }
+ else if (lps->frag_count > auto_litpool_limit)
+ {
+ needed = true;
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ needed = true;
+ }
+ }
+
+ if (needed)
+ {
+ int size = (only_if_needed) ? 3 : 0; /* Space for a "j" insn. */
+ /* Create a potential site for a literal pool. */
+ frag_wane (frag_now);
+ frag_new (0);
+ xtensa_set_frag_assembly_state (frag_now);
+ fragP = frag_now;
+ fragP->tc_frag_data.lit_frchain = frchain_now;
+ fragP->tc_frag_data.literal_frag = fragP;
+ frag_var (rs_machine_dependent, size, size,
+ (only_if_needed) ?
+ RELAX_LITERAL_POOL_CANDIDATE_BEGIN :
+ RELAX_LITERAL_POOL_BEGIN,
+ NULL, 0, NULL);
+ frag_now->tc_frag_data.lit_seg = now_seg;
+ frag_variant (rs_machine_dependent, 0, 0,
+ RELAX_LITERAL_POOL_END, NULL, 0, NULL);
+ xtensa_set_frag_assembly_state (frag_now);
+ }
+ else
+ {
+ /* RELAX_LITERAL_POOL_BEGIN frag is being created;
+ just record it here. */
+ fragP = frag_now;
+ }
+
+ lpf = XNEW (struct litpool_frag);
+ /* Insert at tail of circular list. */
+ lpf->addr = 0;
+ lps->frag_list.prev->next = lpf;
+ lpf->next = &lps->frag_list;
+ lpf->prev = lps->frag_list.prev;
+ lps->frag_list.prev = lpf;
+ 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;
+}
static void
xtensa_cleanup_align_frags (void)
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 *expr = &tinsn->tok[1];
- symbolS *symbolP = expr->X_add_symbol;
- offsetT max_distance = expr->X_add_number;
+ const expressionS *exp = &tinsn->tok[1];
+ symbolS *symbolP = exp->X_add_symbol;
+ offsetT max_distance = exp->X_add_number;
fragS *target_frag;
- if (expr->X_op != O_symbol)
- return FALSE;
+ if (exp->X_op != O_symbol)
+ return false;
target_frag = symbol_get_frag (symbolP);
max_distance += (S_GET_VALUE (symbolP) - target_frag->fr_address);
if (is_branch_jmp_to_next (tinsn, fragP))
- return FALSE;
+ 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;
}
|| fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE))
{
/* Find the loop frag. */
- fragS *targ_frag = next_non_empty_frag (fragP);
+ fragS *loop_frag = next_non_empty_frag (fragP);
/* Find the first insn frag. */
- targ_frag = next_non_empty_frag (targ_frag);
+ fragS *targ_frag = next_non_empty_frag (loop_frag);
+
+ /* Handle a corner case that comes up in hardware
+ diagnostics. The original assembly looks like this:
+
+ loop aX, LabelA
+ <empty_frag>--not found by next_non_empty_frag
+ loop aY, LabelB
+
+ Depending on the start address, the assembler may or
+ may not change it to look something like this:
+
+ loop aX, LabelA
+ nop--frag isn't empty anymore
+ loop aY, LabelB
+
+ So set up to check the alignment of the nop if it
+ exists */
+ while (loop_frag != targ_frag)
+ {
+ if (loop_frag->fr_type == rs_machine_dependent
+ && (loop_frag->fr_subtype == RELAX_ALIGN_NEXT_OPCODE
+ || loop_frag->fr_subtype
+ == RELAX_CHECK_ALIGN_NEXT_OPCODE))
+ targ_frag = loop_frag;
+ else
+ loop_frag = loop_frag->fr_next;
+ }
/* Of course, sometimes (mostly for toy test cases) a
zero-cost loop instruction is the last in a section. */
if (targ_frag)
{
- targ_frag->tc_frag_data.is_first_loop_insn = TRUE;
+ 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
}
+/* When a difference-of-symbols expression is encoded as a uleb128 or
+ sleb128 value, the linker is unable to adjust that value to account for
+ link-time relaxation. Mark all the code between such symbols so that
+ its size cannot be changed by linker relaxation. */
+
+static void
+xtensa_mark_difference_of_two_symbols (void)
+{
+ symbolS *expr_sym;
+
+ for (expr_sym = expr_symbols; expr_sym;
+ expr_sym = symbol_get_tc (expr_sym)->next_expr_symbol)
+ {
+ expressionS *exp = symbol_get_value_expression (expr_sym);
+
+ if (exp->X_op == O_subtract)
+ {
+ symbolS *left = exp->X_add_symbol;
+ symbolS *right = exp->X_op_symbol;
+
+ /* Difference of two symbols not in the same section
+ are handled with relocations in the linker. */
+ if (S_GET_SEGMENT (left) == S_GET_SEGMENT (right))
+ {
+ fragS *start;
+ fragS *end;
+ fragS *walk;
+
+ if (symbol_get_frag (left)->fr_address
+ <= symbol_get_frag (right)->fr_address)
+ {
+ start = symbol_get_frag (left);
+ end = symbol_get_frag (right);
+ }
+ else
+ {
+ start = symbol_get_frag (right);
+ end = symbol_get_frag (left);
+ }
+
+ if (start->tc_frag_data.no_transform_end != NULL)
+ walk = start->tc_frag_data.no_transform_end;
+ else
+ walk = start;
+ do
+ {
+ walk->tc_frag_data.is_no_transform = 1;
+ walk = walk->fr_next;
+ }
+ while (walk && walk->fr_address < end->fr_address);
+
+ start->tc_frag_data.no_transform_end = walk;
+ }
+ }
+ }
+}
+
+
/* Re-process all of the fragments looking to convert all of the
RELAX_ADD_NOP_IF_A0_B_RETW. If the next instruction is a
conditional branch or a retw/retw.n, convert this frag to one that
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;
}
}
frag_wane (fragP);
}
- assert (fragP->fr_type != rs_machine_dependent
+ gas_assert (fragP->fr_type != rs_machine_dependent
|| fragP->fr_subtype != RELAX_ADD_NOP_IF_CLOSE_LOOP_END);
}
}
break;
default:
/* We had darn well better know how big it is. */
- assert (0);
+ gas_assert (0);
break;
}
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)
for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
{
fragS *fragP;
- fragS *current_target = NULL;
xtensa_opcode current_opcode = XTENSA_UNDEFINED;
/* Walk over all of the fragments in a subsection. */
TInsn t_insn;
fragS *loop_frag = next_non_empty_frag (fragP);
tinsn_from_chars (&t_insn, loop_frag->fr_opcode, 0);
- current_target = symbol_get_frag (fragP->fr_symbol);
current_opcode = t_insn.opcode;
- assert (xtensa_opcode_is_loop (xtensa_default_isa,
+ gas_assert (xtensa_opcode_is_loop (xtensa_default_isa,
current_opcode) == 1);
}
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)
{
- char *file_name;
+ const char *file_name;
unsigned line;
frchainS *frchP;
asection *s;
- as_where (&file_name, &line);
+ file_name = as_where (&line);
for (s = stdoutput->sections; s; s = s->next)
for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
{
for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
{
if (fragP->fr_type == rs_machine_dependent
- && fragP->fr_subtype == RELAX_SLOTS
+ && fragP->fr_subtype == RELAX_SLOTS
&& fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED)
{
static xtensa_insnbuf insnbuf = NULL;
/* 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 *expr;
+ const expressionS *exp;
symbolS *symbolP;
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;
- expr = &insn->tok[LOOP_IMMED_OPN];
+ exp = &insn->tok[LOOP_IMMED_OPN];
- if (expr->X_op != O_symbol)
- return FALSE;
+ if (exp->X_op != O_symbol)
+ return false;
- symbolP = expr->X_add_symbol;
+ 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 *expr;
+ const expressionS *exp;
symbolS *symbolP;
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;
- expr = &insn->tok[LOOP_IMMED_OPN];
+ exp = &insn->tok[LOOP_IMMED_OPN];
- if (expr->X_op != O_symbol)
- return FALSE;
+ if (exp->X_op != O_symbol)
+ return false;
- symbolP = expr->X_add_symbol;
+ 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 = xmalloc (100);
+ 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. */
{
if (target_size <= 4)
return 2;
- assert (target_size == 8);
- return 3;
+
+ if (target_size <= 8)
+ return 3;
+
+ if (target_size <= 16)
+ return 4;
+
+ if (target_size <= 32)
+ return 5;
+
+ if (target_size <= 64)
+ return 6;
+
+ if (target_size <= 128)
+ return 7;
+
+ if (target_size <= 256)
+ return 8;
+
+ if (target_size <= 512)
+ return 9;
+
+ if (target_size <= 1024)
+ return 10;
+
+ gas_assert (0);
+ return 0;
}
static int
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);
- assert (target_size > 0 && alignment >= (addressT) target_size);
+ gas_assert (target_size > 0 && alignment >= (addressT) target_size);
if (!use_nops)
{
/* 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
{
== (address + fill + target_size - 1) >> align_pow)
return fill;
}
- assert (0);
+ gas_assert (0);
return 0;
}
static int
branch_align_power (segT sec)
{
- /* If the Xtensa processor has a fetch width of 8 bytes, and the section
- is aligned to at least an 8-byte boundary, then a branch target need
- only fit within an 8-byte aligned block of memory to avoid a stall.
- Otherwise, try to fit branch targets within 4-byte aligned blocks
- (which may be insufficient, e.g., if the section has no alignment, but
- it's good enough). */
- if (xtensa_fetch_width == 8)
- {
- if (get_recorded_alignment (sec) >= 3)
- return 3;
- }
- else
- assert (xtensa_fetch_width == 4);
+ /* If the Xtensa processor has a fetch width of X, and
+ the section is aligned to at least that boundary, then a branch
+ target need only fit within that aligned block of memory to avoid
+ a stall. Otherwise, try to fit branch targets within 4-byte
+ aligned blocks (which may be insufficient, e.g., if the section
+ has no alignment, but it's good enough). */
+ int fetch_align = get_text_align_power(xtensa_fetch_width);
+ int sec_align = get_recorded_alignment (sec);
+
+ if (sec_align >= fetch_align)
+ return fetch_align;
return 2;
}
/* 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;
if (use_no_density)
{
- assert (fill_size % 3 == 0);
+ gas_assert (fill_size % 3 == 0);
return (fill_size / 3);
}
- assert (fill_size != 1); /* Bad argument. */
+ gas_assert (fill_size != 1); /* Bad argument. */
while (fill_size > 1)
{
fill_size -= insn_size;
count++;
}
- assert (fill_size != 1); /* Bad algorithm. */
+ gas_assert (fill_size != 1); /* Bad algorithm. */
return count;
}
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;
if (use_no_density)
return 3;
- assert (fill_size != 1); /* Bad argument. */
+ gas_assert (fill_size != 1); /* Bad argument. */
while (fill_size > 1)
{
if (n + 1 == count)
return insn_size;
}
- assert (0);
+ gas_assert (0);
return 0;
}
int align_power;
fragS *first_insn;
xtensa_opcode opcode;
- bfd_boolean is_loop;
+ bool is_loop;
- assert (fragP->fr_type == rs_machine_dependent);
- assert (fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE);
+ gas_assert (fragP->fr_type == rs_machine_dependent);
+ gas_assert (fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE);
/* Find the loop frag. */
first_insn = next_non_empty_frag (fragP);
first_insn = next_non_empty_frag (first_insn);
is_loop = next_frag_opcode_is_loop (fragP, &opcode);
- assert (is_loop);
+ gas_assert (is_loop);
loop_insn_size = xg_get_single_size (opcode);
pre_opcode_bytes = next_frag_pre_opcode_bytes (fragP);
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;
+ fragS *loop_frag;
- assert (fragP->fr_type == rs_machine_dependent);
+ gas_assert (fragP->fr_type == rs_machine_dependent);
switch (fragP->fr_subtype)
{
case RELAX_DESIRE_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)));
- assert (*max_diff >= opt_diff);
+ gas_assert (*max_diff >= opt_diff);
return opt_diff;
case RELAX_ALIGN_NEXT_OPCODE:
- target_size = get_loop_align_size (next_frag_format_size (fragP));
+ /* The next non-empty frag after this one holds the LOOP instruction
+ that needs to be aligned. The required alignment depends on the
+ size of the next non-empty frag after the loop frag, i.e., the
+ first instruction in the loop. */
+ loop_frag = next_non_empty_frag (fragP);
+ target_size = get_loop_align_size (next_frag_format_size (loop_frag));
loop_insn_offset = 0;
is_loop = next_frag_opcode_is_loop (fragP, &loop_opcode);
- assert (is_loop);
+ gas_assert (is_loop);
/* If the loop has been expanded then the LOOP instruction
could be at an offset from this fragment. */
- if (next_non_empty_frag(fragP)->tc_frag_data.slot_subtypes[0]
- != RELAX_IMMED)
+ if (loop_frag->tc_frag_data.slot_subtypes[0] != RELAX_IMMED)
loop_insn_offset = get_expanded_loop_offset (loop_opcode);
/* In an ideal world, which is what we are shooting for here,
will call get_noop_aligned_address. */
target_address =
address + loop_insn_offset + xg_get_single_size (loop_opcode);
- align_power = get_text_align_power (target_size),
+ 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)
- target_size + opt_diff;
- assert (*max_diff >= opt_diff);
+ gas_assert (*max_diff >= opt_diff);
return opt_diff;
default:
break;
}
- assert (0);
+ gas_assert (0);
return 0;
}
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);
+ (segT, fragS *, long, int, xtensa_format, int, int *, bool);
+
+/* Get projected address for the first fulcrum on a path from source to
+ target. */
+static addressT xg_get_fulcrum (addressT source, addressT target)
+{
+ offsetT delta = target - source;
+ int n;
+
+ n = (labs (delta) + J_RANGE - J_MARGIN - 1) / (J_RANGE - J_MARGIN);
+ return source + delta / n;
+}
+
+/* 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)
+{
+ 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;
+
+ /* Check trampoline frags around the base_tr to find the best. */
+ for (dist = 0; checked; ++dist)
+ {
+ 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;
+ }
+ }
+ }
+
+ 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 bool xg_is_relaxable_fixup (fixS *fixP)
+{
+ xtensa_isa isa = xtensa_default_isa;
+ addressT addr = fixP->fx_frag->fr_address;
+ addressT target;
+ offsetT delta;
+ symbolS *s = fixP->fx_addsy;
+ int slot;
+ xtensa_format fmt;
+ xtensa_opcode opcode;
+
+ 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) + fixP->fx_offset;
+ delta = target - addr;
+
+ if (labs (delta) < J_RANGE - J_MARGIN)
+ return false;
+
+ xtensa_insnbuf_from_chars (isa, trampoline_buf,
+ (unsigned char *) fixP->fx_frag->fr_literal +
+ fixP->fx_where, 0);
+ fmt = xtensa_format_decode (isa, trampoline_buf);
+ gas_assert (fmt != XTENSA_UNDEFINED);
+ 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);
+ return opcode == xtensa_j_opcode;
+}
+
+static void xg_relax_fixups (struct trampoline_seg *ts)
+{
+ struct trampoline_index *idx = &ts->index;
+ segment_info_type *seginfo = seg_info (now_seg);
+ fixS *fx;
+
+ for (fx = seginfo->fix_root; fx; fx = fx->fx_next)
+ {
+ fixS *fixP = fx;
+ struct trampoline_chain *tc = NULL;
+
+ 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);
+ }
+
+ 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);
+ }
+ }
+}
+
+/* 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)
+{
+ struct trampoline_seg *ts = find_trampoline_seg (now_seg);
+
+ 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
input has been stretched already by "stretch". */
xtensa_isa isa = xtensa_default_isa;
int unreported = fragP->tc_frag_data.unreported_expansion;
long new_stretch = 0;
- char *file_name;
+ const char *file_name;
unsigned line;
int lit_size;
static xtensa_insnbuf vbuf = NULL;
int slot, num_slots;
xtensa_format fmt;
- as_where (&file_name, &line);
+ file_name = as_where (&line);
new_logical_line (fragP->fr_file, fragP->fr_line);
fragP->tc_frag_data.unreported_expansion = 0;
case RELAX_LITERAL_NR:
lit_size = 4;
fragP->fr_subtype = RELAX_LITERAL_FINAL;
- assert (unreported == lit_size);
+ gas_assert (unreported == lit_size);
memset (&fragP->fr_literal[fragP->fr_fix], 0, 4);
fragP->fr_var -= lit_size;
fragP->fr_fix += lit_size;
case RELAX_IMMED:
case RELAX_IMMED_STEP1:
case RELAX_IMMED_STEP2:
+ case RELAX_IMMED_STEP3:
/* Place the immediate. */
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:
break;
case RELAX_LITERAL_POOL_BEGIN:
+ if (fragP->fr_var != 0)
+ {
+ /* We have a converted "candidate" literal pool;
+ assemble a jump around it. */
+ TInsn insn;
+ if (!litpool_slotbuf)
+ {
+ litpool_buf = xtensa_insnbuf_alloc (isa);
+ 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;
+ tinsn_init (&insn);
+ insn.insn_type = ITYPE_INSN;
+ insn.opcode = xtensa_j_opcode;
+ insn.ntok = 1;
+ set_expr_symbol_offset (&insn.tok[0], fragP->fr_symbol,
+ fragP->fr_fix);
+ fmt = xg_get_single_format (xtensa_j_opcode);
+ tinsn_to_slotbuf (fmt, 0, &insn, litpool_slotbuf);
+ xtensa_format_set_slot (isa, fmt, 0, litpool_buf, litpool_slotbuf);
+ xtensa_insnbuf_to_chars (isa, litpool_buf,
+ (unsigned char *)fragP->fr_literal +
+ fragP->fr_fix, 3);
+ fragP->fr_fix += 3;
+ fragP->fr_var -= 3;
+ /* Add a fix-up. */
+ fix_new (fragP, 0, 3, fragP->fr_symbol, 0, true,
+ BFD_RELOC_XTENSA_SLOT0_OP);
+ }
+ break;
+
case RELAX_LITERAL_POOL_END:
+ case RELAX_LITERAL_POOL_CANDIDATE_BEGIN:
case RELAX_MAYBE_UNREACHABLE:
case RELAX_MAYBE_DESIRE_ALIGN:
/* No relaxation required. */
new_stretch += relax_frag_for_align (fragP, stretch);
break;
+ case RELAX_TRAMPOLINE:
+ if (fragP->tc_frag_data.relax_seen)
+ xg_relax_trampoline (fragP, stretch, &new_stretch);
+ break;
+
default:
as_bad (_("bad relaxation state"));
}
/* 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)
{
long stretch_me;
long diff;
- assert (fragP->fr_subtype == RELAX_FILL_NOP
+ gas_assert (fragP->fr_subtype == RELAX_FILL_NOP
|| fragP->fr_subtype == RELAX_UNREACHABLE
|| (fragP->fr_subtype == RELAX_SLOTS
&& fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW));
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:
(*widens)++;
break;
}
- address += total_frag_text_expansion (fragP);;
+ address += total_frag_text_expansion (fragP);
break;
case RELAX_IMMED:
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;
{
local_opt_diff = get_aligned_diff (fragP, address, &max_diff);
opt_diff = local_opt_diff;
- assert (opt_diff >= 0);
- assert (max_diff >= opt_diff);
+ gas_assert (opt_diff >= 0);
+ gas_assert (max_diff >= opt_diff);
if (max_diff == 0)
return 0;
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. */
{
if (this_frag->fr_subtype == RELAX_UNREACHABLE)
{
- assert (opt_diff <= UNREACHABLE_MAX_WIDTH);
+ gas_assert (opt_diff <= (signed) xtensa_fetch_width);
return opt_diff;
}
return 0;
if (this_frag->fr_subtype == RELAX_SLOTS
&& this_frag->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
- assert (stretch_amount <= 1);
+ gas_assert (stretch_amount <= 1);
else if (this_frag->fr_subtype == RELAX_FILL_NOP)
{
if (this_frag->tc_frag_data.is_no_density)
- assert (stretch_amount == 3 || stretch_amount == 0);
+ gas_assert (stretch_amount == 3 || stretch_amount == 0);
else
- assert (stretch_amount <= 3);
+ gas_assert (stretch_amount <= 3);
}
}
return stretch_amount;
/* The idea: widen everything you can to get a target or loop aligned,
then start using NOPs.
- When we must have a NOP, here is a table of how we decide
- (so you don't have to fight through the control flow below):
-
wide_nops = the number of wide NOPs available for aligning
narrow_nops = the number of narrow NOPs available for aligning
(a subset of wide_nops)
widens = the number of narrow instructions that should be widened
- Desired wide narrow
- Diff nop nop widens
- 1 0 0 1
- 2 0 1 0
- 3a 1 0 0
- b 0 1 1 (case 3a makes this case unnecessary)
- 4a 1 0 1
- b 0 2 0
- c 0 1 2 (case 4a makes this case unnecessary)
- 5a 1 0 2
- b 1 1 0
- c 0 2 1 (case 5b makes this case unnecessary)
- 6a 2 0 0
- b 1 0 3
- c 0 1 4 (case 6b makes this case unnecessary)
- d 1 1 1 (case 6a makes this case unnecessary)
- e 0 2 2 (case 6a makes this case unnecessary)
- f 0 3 0 (case 6a makes this case unnecessary)
- 7a 1 0 4
- b 2 0 1
- c 1 1 2 (case 7b makes this case unnecessary)
- d 0 1 5 (case 7a makes this case unnecessary)
- e 0 2 3 (case 7b makes this case unnecessary)
- f 0 3 1 (case 7b makes this case unnecessary)
- g 1 2 1 (case 7b makes this case unnecessary)
*/
static long
int num_widens,
int desired_diff)
{
+ int nops_needed;
+ int nop_bytes;
+ int extra_bytes;
int bytes_short = desired_diff - num_widens;
- assert (desired_diff >= 0 && desired_diff < 8);
+ gas_assert (desired_diff >= 0
+ && desired_diff < (signed) xtensa_fetch_width);
if (desired_diff == 0)
return 0;
- assert (wide_nops > 0 || num_widens > 0);
+ gas_assert (wide_nops > 0 || num_widens > 0);
/* Always prefer widening to NOP-filling. */
if (bytes_short < 0)
/* From here we will need at least one NOP to get an alignment.
However, we may not be able to align at all, in which case,
don't widen. */
- if (this_frag->fr_subtype == RELAX_FILL_NOP)
+ nops_needed = desired_diff / 3;
+
+ /* If there aren't enough nops, don't widen. */
+ if (nops_needed > wide_nops)
+ return 0;
+
+ /* First try it with all wide nops. */
+ nop_bytes = nops_needed * 3;
+ extra_bytes = desired_diff - nop_bytes;
+
+ if (nop_bytes + num_widens >= desired_diff)
{
- switch (desired_diff)
- {
- case 1:
- return 0;
- case 2:
- if (!this_frag->tc_frag_data.is_no_density && narrow_nops == 1)
- return 2; /* case 2 */
- return 0;
- case 3:
- if (wide_nops > 1)
- return 0;
- else
- return 3; /* case 3a */
- case 4:
- if (num_widens >= 1 && wide_nops == 1)
- return 3; /* case 4a */
- if (!this_frag->tc_frag_data.is_no_density && narrow_nops == 2)
- return 2; /* case 4b */
- return 0;
- case 5:
- if (num_widens >= 2 && wide_nops == 1)
- return 3; /* case 5a */
- /* We will need two nops. Are there enough nops
- between here and the align target? */
- if (wide_nops < 2 || narrow_nops == 0)
- return 0;
- /* Are there other nops closer that can serve instead? */
- if (wide_nops > 2 && narrow_nops > 1)
- return 0;
- /* Take the density one first, because there might not be
- another density one available. */
- if (!this_frag->tc_frag_data.is_no_density)
- return 2; /* case 5b narrow */
- else
- return 3; /* case 5b wide */
- return 0;
- case 6:
- if (wide_nops == 2)
- return 3; /* case 6a */
- else if (num_widens >= 3 && wide_nops == 1)
- return 3; /* case 6b */
- return 0;
- case 7:
- if (wide_nops == 1 && num_widens >= 4)
- return 3; /* case 7a */
- else if (wide_nops == 2 && num_widens >= 1)
- return 3; /* case 7b */
- return 0;
- default:
- assert (0);
- }
+ if (this_frag->fr_subtype == RELAX_FILL_NOP)
+ return 3;
+ else if (num_widens == extra_bytes)
+ return 1;
+ return 0;
}
- else
+
+ /* Add a narrow nop. */
+ nops_needed++;
+ nop_bytes += 2;
+ extra_bytes -= 2;
+ if (narrow_nops == 0 || nops_needed > wide_nops)
+ return 0;
+
+ if (nop_bytes + num_widens >= desired_diff && extra_bytes >= 0)
{
- /* We will need a NOP no matter what, but should we widen
- this instruction to help?
+ if (this_frag->fr_subtype == RELAX_FILL_NOP)
+ return !this_frag->tc_frag_data.is_no_density ? 2 : 3;
+ else if (num_widens == extra_bytes)
+ return 1;
+ return 0;
+ }
- This is a RELAX_NARROW frag. */
- switch (desired_diff)
- {
- case 1:
- assert (0);
- return 0;
- case 2:
- case 3:
- return 0;
- case 4:
- if (wide_nops >= 1 && num_widens == 1)
- return 1; /* case 4a */
- return 0;
- case 5:
- if (wide_nops >= 1 && num_widens == 2)
- return 1; /* case 5a */
- return 0;
- case 6:
- if (wide_nops >= 2)
- return 0; /* case 6a */
- else if (wide_nops >= 1 && num_widens == 3)
- return 1; /* case 6b */
- return 0;
- case 7:
- if (wide_nops >= 1 && num_widens == 4)
- return 1; /* case 7a */
- else if (wide_nops >= 2 && num_widens == 1)
- return 1; /* case 7b */
- return 0;
- default:
- assert (0);
- return 0;
- }
+ /* Replace a wide nop with a narrow nop--we can get here if
+ extra_bytes was negative in the previous conditional. */
+ if (narrow_nops == 1)
+ return 0;
+ nop_bytes--;
+ extra_bytes++;
+ if (nop_bytes + num_widens >= desired_diff)
+ {
+ if (this_frag->fr_subtype == RELAX_FILL_NOP)
+ return !this_frag->tc_frag_data.is_no_density ? 2 : 3;
+ else if (num_widens == extra_bytes)
+ return 1;
+ return 0;
+ }
+
+ /* If we can't satisfy any of the above cases, then we can't align
+ using padding or fill nops. */
+ return 0;
+}
+
+
+static fragS *
+xg_find_best_trampoline_for_tinsn (TInsn *tinsn, fragS *fragP)
+{
+ symbolS *sym = tinsn->tok[0].X_add_symbol;
+ 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;
+
+ if (!ts || !ts->index.n_entries)
+ return NULL;
+
+ i = xg_find_best_trampoline (&ts->index, source, target);
+
+ return ts->index.entry[i];
+}
+
+
+/* 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)
+{
+ fixS *fixP;
+ TInsn insn;
+ xtensa_format fmt;
+ xtensa_isa isa = xtensa_default_isa;
+
+ 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;
+
+ /* 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;
+
+ /* Do we have room for more? */
+ if (xg_is_trampoline_frag_full (fragP))
+ {
+ frag_wane (fragP);
+ fragP->fr_subtype = 0;
+ }
+
+ return fixP;
+}
+
+
+static int
+init_trampoline_frag (fragS *fp)
+{
+ 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, fp, 0);
+ fp->fr_symbol = lsym;
+ if (fp->tc_frag_data.needs_jump_around)
+ {
+ fp->tc_frag_data.jump_around_fix = xg_append_jump (fp, lsym, 3);
+ growth = 3;
+ }
+ }
+ return growth;
+}
+
+static int
+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)
+{
+ int slot = xg_get_single_symbol_slot (origfrag);
+ fixS *fixP;
+
+ /* Assemble a jump to the target label in the trampoline frag. */
+ 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[slot] = tramp->fr_symbol;
+ origfrag->tc_frag_data.slot_offsets[slot] = tramp->fr_fix - 3;
+
+ /* If trampoline is full, remove it from the list. */
+ 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);
+
+ gas_assert (ts->index.entry[tr] == tramp);
+ xg_remove_trampoline_from_index (&ts->index, tr);
}
- assert (0);
- return 0;
+
+ 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 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;
int num_steps;
- fragS *lit_fragP;
int num_text_bytes, num_literal_bytes;
- int literal_diff, total_text_diff, this_text_diff, first;
+ int literal_diff, total_text_diff, this_text_diff;
- assert (fragP->fr_opcode != NULL);
+ gas_assert (fragP->fr_opcode != NULL);
xg_clear_vinsn (&cur_vinsn);
vinsn_from_chars (&cur_vinsn, fragP->fr_opcode);
if (cur_vinsn.num_slots > 1)
- wide_insn = TRUE;
+ from_wide_insn = true;
tinsn = cur_vinsn.slots[slot];
tinsn_immed_from_frag (&tinsn, fragP, slot);
istack_init (&istack);
num_steps = xg_assembly_relax (&istack, &tinsn, segP, fragP, frag_offset,
min_steps, stretch);
- if (num_steps < min_steps)
- {
- as_fatal (_("internal error: relaxation failed"));
- return 0;
- }
-
- if (num_steps > RELAX_IMMED_MAXSTEPS)
- {
- as_fatal (_("internal error: relaxation requires too many steps"));
- return 0;
- }
+ gas_assert (num_steps >= min_steps && num_steps <= RELAX_IMMED_MAXSTEPS);
fragP->tc_frag_data.slot_subtypes[slot] = (int) RELAX_IMMED + num_steps;
/* Figure out the number of bytes needed. */
- lit_fragP = 0;
num_literal_bytes = get_num_stack_literal_bytes (&istack);
- literal_diff =
- num_literal_bytes - fragP->tc_frag_data.literal_expansion[slot];
- first = 0;
- while (istack.insn[first].opcode == XTENSA_UNDEFINED)
- first++;
+ literal_diff
+ = num_literal_bytes - fragP->tc_frag_data.literal_expansion[slot];
num_text_bytes = get_num_stack_text_bytes (&istack);
- if (wide_insn)
+
+ if (from_wide_insn)
{
+ int first = 0;
+ while (istack.insn[first].opcode == XTENSA_UNDEFINED)
+ first++;
+
num_text_bytes += old_size;
if (opcode_fits_format_slot (istack.insn[first].opcode, fmt, slot))
num_text_bytes -= xg_get_single_size (istack.insn[first].opcode);
+ else
+ {
+ /* The first instruction in the relaxed sequence will go after
+ the current wide instruction, and thus its symbolic immediates
+ might not fit. */
+
+ istack_init (&istack);
+ num_steps = xg_assembly_relax (&istack, &tinsn, segP, fragP,
+ frag_offset + old_size,
+ min_steps, stretch + old_size);
+ gas_assert (num_steps >= min_steps && num_steps <= RELAX_IMMED_MAXSTEPS);
+
+ fragP->tc_frag_data.slot_subtypes[slot]
+ = (int) RELAX_IMMED + num_steps;
+
+ num_literal_bytes = get_num_stack_literal_bytes (&istack);
+ literal_diff
+ = num_literal_bytes - fragP->tc_frag_data.literal_expansion[slot];
+
+ num_text_bytes = get_num_stack_text_bytes (&istack) + old_size;
+ }
}
+
total_text_diff = num_text_bytes - old_size;
this_text_diff = total_text_diff - fragP->tc_frag_data.text_expansion[slot];
/* It MUST get larger. If not, we could get an infinite loop. */
- assert (num_text_bytes >= 0);
- assert (literal_diff >= 0);
- assert (total_text_diff >= 0);
+ gas_assert (num_text_bytes >= 0);
+ gas_assert (literal_diff >= 0);
+ gas_assert (total_text_diff >= 0);
fragP->tc_frag_data.text_expansion[slot] = total_text_diff;
fragP->tc_frag_data.literal_expansion[slot] = num_literal_bytes;
- assert (fragP->tc_frag_data.text_expansion[slot] >= 0);
- assert (fragP->tc_frag_data.literal_expansion[slot] >= 0);
+ gas_assert (fragP->tc_frag_data.text_expansion[slot] >= 0);
+ gas_assert (fragP->tc_frag_data.literal_expansion[slot] >= 0);
/* Find the associated expandable literal for this. */
if (literal_diff != 0)
{
- lit_fragP = fragP->tc_frag_data.literal_frags[slot];
+ fragS *lit_fragP = fragP->tc_frag_data.literal_frags[slot];
if (lit_fragP)
{
- assert (literal_diff == 4);
+ gas_assert (literal_diff == 4);
lit_fragP->tc_frag_data.unreported_expansion += literal_diff;
/* We expect that the literal section state has NOT been
modified yet. */
- assert (lit_fragP->fr_type == rs_machine_dependent
+ gas_assert (lit_fragP->fr_type == rs_machine_dependent
&& lit_fragP->fr_subtype == RELAX_LITERAL);
lit_fragP->fr_subtype = RELAX_LITERAL_NR;
if (negatable_branch && istack.ninsn > 1)
update_next_frag_state (fragP);
+ /* If last insn is a jump, and it cannot reach its target, try to find a trampoline. */
+ if (istack.ninsn > 2 &&
+ istack.insn[istack.ninsn - 1].insn_type == ITYPE_LABEL &&
+ istack.insn[istack.ninsn - 2].insn_type == ITYPE_INSN &&
+ 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 (ts &&
+ !xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset,
+ total_text_diff))
+ {
+ 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)
+ {
+ 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
+ {
+ /* If target symbol is undefined, assume it will reach once linked. */
+ expressionS *exp = &istack.insn[istack.ninsn - 2].tok[0];
+
+ if (exp->X_op == O_symbol && S_IS_DEFINED (exp->X_add_symbol))
+ {
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("jump target out of range; no usable trampoline found"));
+ }
+ }
+ }
+ }
+
return this_text_diff;
}
int slot;
int num_slots;
xtensa_format fmt;
- char *file_name;
+ const char *file_name;
unsigned line;
- as_where (&file_name, &line);
+ file_name = as_where (&line);
new_logical_line (fragp->fr_file, fragp->fr_line);
switch (fragp->fr_subtype)
case RELAX_IMMED:
case RELAX_IMMED_STEP1:
case RELAX_IMMED_STEP2:
+ case RELAX_IMMED_STEP3:
/* Place the immediate. */
convert_frag_immed
(sec, fragp,
fragS *f;
fragp->fr_subtype = RELAX_LITERAL_FINAL;
- assert (fragp->tc_frag_data.unreported_expansion == 4);
+ gas_assert (fragp->tc_frag_data.unreported_expansion == 4);
memset (&fragp->fr_literal[fragp->fr_fix], 0, 4);
fragp->fr_var -= 4;
fragp->fr_fix += 4;
else
as_bad (_("invalid relaxation fragment result"));
break;
+
+ case RELAX_TRAMPOLINE:
+ break;
}
fragp->fr_var = 0;
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;
int size, old_size, diff;
offsetT frag_offset;
- assert (slot == 0);
+ gas_assert (slot == 0);
tinsn_from_chars (&tinsn, fragP->fr_opcode, 0);
if (fragP->tc_frag_data.is_aligning_branch == 1)
{
- assert (fragP->tc_frag_data.text_expansion[0] == 1
+ gas_assert (fragP->tc_frag_data.text_expansion[0] == 1
|| fragP->tc_frag_data.text_expansion[0] == 0);
convert_frag_immed (segP, fragP, fragP->tc_frag_data.text_expansion[0],
fmt, slot);
return;
}
- assert (fragP->fr_opcode != NULL);
+ gas_assert (fragP->fr_opcode != NULL);
/* Frags in this relaxation state should only contain
single instruction bundles. */
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;
- assert (diff >= 0);
- assert (diff <= fragP->fr_var);
+ gas_assert (diff >= 0);
+ gas_assert (diff <= fragP->fr_var);
fragP->fr_var -= diff;
fragP->fr_fix += diff;
{
char *loc = &fragP->fr_literal[fragP->fr_fix];
int size = fragP->tc_frag_data.text_expansion[0];
- assert ((unsigned) size == (fragP->fr_next->fr_address
+ gas_assert ((unsigned) size == (fragP->fr_next->fr_address
- fragP->fr_address - fragP->fr_fix));
if (size == 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 wide_insn = FALSE;
+ bool from_wide_insn = false;
int bytes;
- bfd_boolean is_loop;
+ bool is_loop;
- assert (fr_opcode != NULL);
+ gas_assert (fr_opcode != NULL);
xg_clear_vinsn (&cur_vinsn);
vinsn_from_chars (&cur_vinsn, fr_opcode);
if (cur_vinsn.num_slots > 1)
- wide_insn = TRUE;
+ from_wide_insn = true;
orig_tinsn = cur_vinsn.slots[slot];
tinsn_immed_from_frag (&orig_tinsn, fragP, slot);
else
{
bytes += fragP->tc_frag_data.text_expansion[0];
- assert (bytes == 2 || bytes == 3);
+ gas_assert (bytes == 2 || bytes == 3);
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;
- bfd_boolean last_is_jump;
+ bool first = true;
/* It does not fit. Find something that does and
convert immediately. */
unreach = unreach->fr_next;
}
- assert (unreach->fr_type == rs_machine_dependent
+ gas_assert (unreach->fr_type == rs_machine_dependent
&& (unreach->fr_subtype == RELAX_MAYBE_UNREACHABLE
|| unreach->fr_subtype == RELAX_UNREACHABLE));
target_offset += unreach->tc_frag_data.text_expansion[0];
}
- assert (gen_label == NULL);
- gen_label = symbol_new (FAKE_LABEL_NAME, now_seg,
+ gas_assert (gen_label == NULL);
+ 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 && wide_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;
- last_is_jump = FALSE;
+ first = true;
for (i = 0; i < istack.ninsn; i++)
{
TInsn *tinsn = &istack.insn[i];
case ITYPE_LITERAL:
lit_frag = fragP->tc_frag_data.literal_frags[slot];
/* Already checked. */
- assert (lit_frag != NULL);
- assert (lit_sym != NULL);
- assert (tinsn->ntok == 1);
+ gas_assert (lit_frag != NULL);
+ gas_assert (lit_sym != NULL);
+ gas_assert (tinsn->ntok == 1);
/* Add a fixup. */
target_seg = S_GET_SEGMENT (lit_sym);
- assert (target_seg);
- reloc_type = map_operator_to_reloc (tinsn->tok[0].X_op);
+ gas_assert (target_seg);
+ 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:
case ITYPE_INSN:
xg_resolve_labels (tinsn, gen_label);
xg_resolve_literals (tinsn, lit_sym);
- if (wide_insn && first)
+ 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;
- assert (diff >= 0);
+ gas_assert (diff >= 0);
if (diff != 0)
- expanded = TRUE;
- assert (diff <= fragP->fr_var);
+ 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);
}
}
segT seg = now_seg;
subsegT subseg = now_subseg;
- assert (new_seg != 0);
+ gas_assert (new_seg != 0);
subseg_set (new_seg, new_subseg);
new_fix = fix_new_exp (frag, where, size, exp, pcrel, r_type);
}
-/* 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);
-
- assert (xtensa_opcode_is_loop (isa, loop_insn.opcode) == 1);
- addi_offset += loop_offset;
- addmi_offset += loop_offset;
-
- 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;
- 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);
- assert (addi_insn.opcode == xtensa_addi_opcode);
-
- tinsn_from_chars (&addmi_insn, fragP->fr_opcode + addmi_offset, 0);
- 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
static subseg_map *
add_subseg_info (segT seg, subsegT subseg)
{
- subseg_map *subseg_e = (subseg_map *) xmalloc (sizeof (subseg_map));
+ subseg_map *subseg_e = XNEW (subseg_map);
memset (subseg_e, 0, sizeof (subseg_map));
subseg_e->seg = seg;
subseg_e->subseg = subseg;
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)
segT literal_section = head->seg;
/* Move the literal section to the front of the section list. */
- assert (literal_section);
+ gas_assert (literal_section);
if (literal_section != stdoutput->sections)
{
bfd_section_list_remove (stdoutput, literal_section);
static void mark_literal_frags (seg_list *);
+static void
+xg_promote_candidate_litpool (struct litpool_seg *lps,
+ struct litpool_frag *lp)
+{
+ fragS *poolbeg;
+ fragS *poolend;
+ symbolS *lsym;
+ char label[10 + 2 * sizeof (fragS *)];
+
+ 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. */
+}
+
+static struct litpool_frag *xg_find_litpool (struct litpool_seg *lps,
+ struct litpool_frag *lpf,
+ addressT addr)
+{
+ struct litpool_frag *lp = lpf->prev;
+
+ 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)
+ {
+ frchainS *frchP = seg_info (lps->seg)->frchainP;
+ 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;
+ for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+ {
+ if (lpf && fragP == lpf->fragP)
+ {
+ gas_assert(fragP->fr_type == rs_machine_dependent &&
+ (fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN ||
+ fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN));
+ /* Found a litpool location. */
+ lpf->addr = addr;
+ lpf = lpf->next;
+ }
+ if (fragP->fr_type == rs_machine_dependent &&
+ fragP->fr_subtype == RELAX_SLOTS)
+ {
+ int slot;
+ for (slot = 0; slot < MAX_SLOTS; 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 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;
+ }
+ }
+ }
+ addr += fragP->fr_fix;
+ if (fragP->fr_type == rs_fill)
+ addr += fragP->fr_offset;
+ }
+ }
+ }
+}
+
static void
xtensa_move_literals (void)
{
seg_list *segment;
frchainS *frchain_from, *frchain_to;
- fragS *search_frag, *next_frag, *last_frag, *literal_pool, *insert_after;
+ 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);
+
/* Keep the literals for .init and .fini in separate sections. */
- if (!strcmp (segment_name (segment->seg), INIT_SECTION_NAME)
- || !strcmp (segment_name (segment->seg), FINI_SECTION_NAME))
+ if ((!memcmp (seg_name, init_name, init_name_len) &&
+ !strcmp (seg_name + init_name_len, ".literal")) ||
+ (!memcmp (seg_name, fini_name, fini_name_len) &&
+ !strcmp (seg_name + fini_name_len, ".literal")))
continue;
frchain_from = seg_info (segment->seg)->frchainP;
frchain_to = NULL;
frag_splice = &(frchain_from->frch_root);
- while (!search_frag->tc_frag_data.literal_frag)
+ while (search_frag && !search_frag->tc_frag_data.literal_frag)
{
- assert (search_frag->fr_fix == 0
+ gas_assert (search_frag->fr_fix == 0
|| search_frag->fr_type == rs_align);
search_frag = search_frag->fr_next;
}
- assert (search_frag->tc_frag_data.literal_frag->fr_subtype
+ if (!search_frag)
+ continue;
+
+ gas_assert (search_frag->tc_frag_data.literal_frag->fr_subtype
== RELAX_LITERAL_POOL_BEGIN);
xtensa_switch_section_emit_state (&state, segment->seg, 0);
frags in it. */
frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
xtensa_set_frag_assembly_state (frag_now);
- last_frag = frag_now;
frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
xtensa_set_frag_assembly_state (frag_now);
while (search_frag != frag_now)
{
next_frag = search_frag->fr_next;
-
- /* First, move the frag out of the literal section and
- to the appropriate place. */
if (search_frag->tc_frag_data.literal_frag)
{
literal_pool = search_frag->tc_frag_data.literal_frag;
- assert (literal_pool->fr_subtype == RELAX_LITERAL_POOL_BEGIN);
+ gas_assert (literal_pool->fr_subtype == RELAX_LITERAL_POOL_BEGIN);
frchain_to = literal_pool->tc_frag_data.lit_frchain;
- assert (frchain_to);
+ gas_assert (frchain_to);
+ }
+
+ if (search_frag->fr_type == rs_fill && search_frag->fr_fix == 0)
+ {
+ /* Skip empty fill frags. */
+ *frag_splice = next_frag;
+ search_frag = next_frag;
+ continue;
}
- insert_after = literal_pool;
- while (insert_after->fr_next->fr_subtype != RELAX_LITERAL_POOL_END)
- insert_after = insert_after->fr_next;
+ if (search_frag->fr_type == rs_align)
+ {
+ /* Skip alignment frags, because the pool as a whole will be
+ aligned if used, and we don't want to force alignment if the
+ pool is unused. */
+ *frag_splice = next_frag;
+ search_frag = next_frag;
+ continue;
+ }
+
+ /* First, move the frag out of the literal section and
+ to the appropriate place. */
+ /* 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)
+ {
+ segT pool_seg = literal_pool->fr_next->tc_frag_data.lit_seg;
+ emit_state prev_state;
+ fragS *prev_frag;
+ fragS *align_frag;
+ xtensa_switch_section_emit_state (&prev_state, pool_seg, 0);
+ prev_frag = frag_now;
+ frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
+ align_frag = frag_now;
+ frag_align (2, 0, 0);
+ /* Splice it into the right place. */
+ prev_frag->fr_next = align_frag->fr_next;
+ align_frag->fr_next = literal_pool->fr_next;
+ literal_pool->fr_next = align_frag;
+ /* Insert after this one. */
+ literal_pool->tc_frag_data.literal_frag = align_frag;
+ xtensa_restore_emit_state (&prev_state);
+ }
+ insert_after = literal_pool->tc_frag_data.literal_frag;
dest_seg = insert_after->fr_next->tc_frag_data.lit_seg;
+ /* Skip align frag. */
+ if (insert_after->fr_next->fr_type == rs_align)
+ {
+ insert_after = insert_after->fr_next;
+ }
*frag_splice = next_frag;
search_frag->fr_next = insert_after->fr_next;
insert_after->fr_next = search_frag;
search_frag->tc_frag_data.lit_seg = dest_seg;
+ literal_pool->tc_frag_data.literal_frag = search_frag;
/* Now move any fixups associated with this frag to the
right section. */
frchain_from = seg_info (segment->seg)->frchainP;
as_warn (_("fixes not all moved from %s"), segment->seg->name);
- assert (frchain_from->fix_root == NULL);
+ gas_assert (frchain_from->fix_root == NULL);
}
frchain_from->fix_tail = NULL;
xtensa_restore_emit_state (&state);
for (lit = literal_syms; lit; lit = lit->next)
{
symbolS *lit_sym = lit->sym;
- segT dest_seg = symbol_get_frag (lit_sym)->tc_frag_data.lit_seg;
- if (dest_seg)
- S_SET_SEGMENT (lit_sym, dest_seg);
+ segT dseg = symbol_get_frag (lit_sym)->tc_frag_data.lit_seg;
+ if (dseg)
+ S_SET_SEGMENT (lit_sym, dseg);
}
}
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;
segT literal_section = head->seg;
/* Move the literal section after "after". */
- assert (literal_section);
+ gas_assert (literal_section);
if (literal_section != after)
{
bfd_section_list_remove (stdoutput, literal_section);
/* Now perform the final error check. */
for (sec = stdoutput->sections; sec != NULL; sec = sec->next)
new_count++;
- assert (new_count == old_count);
+ gas_assert (new_count == old_count);
}
{
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)
{
- 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;
+ if (!auto_litpools)
+ {
+ as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
+ }
+ 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;
const char *group_name = elf_group_name (sec);
-
+
return (group_name == gname
|| (group_name != NULL
&& gname != NULL
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;
- char *base_name, *name, *suffix;
+ const char *base_name, *suffix;
+ char *name;
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;
if (*pcached)
return *pcached;
-
+
text_name = default_lit_sections.lit_prefix;
if (! text_name || ! *text_name)
{
base_name = use_abs_literals ? ".lit4" : ".literal";
if (group_name)
{
- name = xmalloc (strlen (base_name) + strlen (group_name) + 2);
- sprintf (name, "%s.%s", base_name, group_name);
+ name = concat (base_name, ".", group_name, (char *) NULL);
}
else if (strncmp (text_name, ".gnu.linkonce.", linkonce_len) == 0)
{
suffix = strchr (text_name + linkonce_len, '.');
- name = xmalloc (linkonce_len + strlen (base_name) + 1
- + (suffix ? strlen (suffix) : 0));
- strcpy (name, ".gnu.linkonce");
- strcat (name, base_name);
- if (suffix)
- strcat (name, suffix);
- linkonce = TRUE;
+ name = concat (".gnu.linkonce", base_name, suffix ? suffix : "",
+ (char *) NULL);
+ linkonce = true;
}
else
{
- /* If the section name ends with ".text", then replace that suffix
- instead of appending an additional suffix. */
+ /* If the section name begins or ends with ".text", then replace
+ that portion instead of appending an additional suffix. */
size_t len = strlen (text_name);
- if (len >= 5 && strcmp (text_name + len - 5, ".text") == 0)
+ if (len >= 5
+ && (strcmp (text_name + len - 5, ".text") == 0
+ || startswith (text_name, ".text")))
len -= 5;
- name = xmalloc (len + strlen (base_name) + 1);
- strcpy (name, text_name);
- strcpy (name + len, base_name);
+ name = XNEWVEC (char, len + strlen (base_name) + 1);
+ if (startswith (text_name, ".text"))
+ {
+ strcpy (name, base_name);
+ strcat (name, text_name + 5);
+ }
+ else
+ {
+ strcpy (name, text_name);
+ strcpy (name + len, base_name);
+ }
}
/* Canonicalize section names to allow renaming literal sections.
if (! use_abs_literals)
{
/* Add the newly created literal segment to the list. */
- seg_list *n = (seg_list *) xmalloc (sizeof (seg_list));
+ seg_list *n = XNEW (seg_list);
n->seg = seg;
n->next = literal_head->next;
literal_head->next = n;
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 segment_info_type *retrieve_segment_info (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, segT, xtensa_block_info **, frag_predicate, frag_predicate);
-static bfd_boolean xtensa_frag_flags_is_empty (const frag_flags *);
+ (segT, xtensa_block_info **, frag_predicate, frag_predicate);
+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 bfd_vma frag_flags_to_number (const frag_flags *);
-static void add_xt_prop_frags
- (segT, segT, xtensa_block_info **, frag_flags_fn);
+static flagword frag_flags_to_number (const frag_flags *);
+static void add_xt_prop_frags (segT, xtensa_block_info **, frag_flags_fn);
/* Set up property tables after relaxation. */
xtensa_find_unmarked_state_frags ();
xtensa_mark_frags_for_org ();
+ xtensa_mark_difference_of_two_symbols ();
xtensa_create_property_segments (get_frag_is_literal,
NULL,
/* This function is only meaningful after xtensa_move_literals. */
-static bfd_boolean
+static bool
get_frag_is_literal (const fragS *fragP)
{
- assert (fragP != NULL);
+ gas_assert (fragP != NULL);
return fragP->tc_frag_data.is_literal;
}
seclist = &(*seclist)->next)
{
segT sec = *seclist;
- flagword flags;
- flags = bfd_get_section_flags (stdoutput, sec);
- if (flags & SEC_DEBUGGING)
- continue;
- if (!(flags & SEC_ALLOC))
+ if (exclude_section_from_property_tables (sec))
continue;
if (section_has_property (sec, property_function))
{
- segT insn_sec =
- xtensa_get_property_section (sec, section_name_base);
- segment_info_type *xt_seg_info = retrieve_segment_info (insn_sec);
- xtensa_block_info **xt_blocks =
- &xt_seg_info->tc_segment_info_data.blocks[sec_type];
+ segment_info_type *xt_seg_info;
+ xtensa_block_info **xt_blocks;
+ segT prop_sec = xtensa_make_property_section (sec, section_name_base);
+
+ prop_sec->output_section = prop_sec;
+ subseg_set (prop_sec, 0);
+ xt_seg_info = seg_info (prop_sec);
+ xt_blocks = &xt_seg_info->tc_segment_info_data.blocks[sec_type];
+
/* Walk over all of the frchains here and add new sections. */
- add_xt_block_frags (sec, insn_sec, xt_blocks, property_function,
+ add_xt_block_frags (sec, xt_blocks, property_function,
end_property_function);
}
}
if (block)
{
xtensa_block_info *cur_block;
- /* This is a section with some data. */
int num_recs = 0;
bfd_size_type rec_size;
num_recs++;
rec_size = num_recs * 8;
- bfd_set_section_size (stdoutput, sec, rec_size);
-
- /* In order to make this work with the assembler, we have to
- build some frags and then build the "fixups" for it. It
- would be easier to just set the contents then set the
- arlents. */
+ bfd_set_section_size (sec, rec_size);
if (num_recs)
{
- /* Allocate a fragment and leak it. */
- fragS *fragP;
- bfd_size_type frag_size;
- fixS *fixes;
- frchainS *frchainP;
- int i;
char *frag_data;
+ int i;
- frag_size = sizeof (fragS) + rec_size;
- fragP = (fragS *) xmalloc (frag_size);
-
- memset (fragP, 0, frag_size);
- fragP->fr_address = 0;
- fragP->fr_next = NULL;
- fragP->fr_fix = rec_size;
- fragP->fr_var = 0;
- fragP->fr_type = rs_fill;
- /* The rest are zeros. */
-
- frchainP = seginfo->frchainP;
- frchainP->frch_root = fragP;
- frchainP->frch_last = fragP;
-
- fixes = (fixS *) xmalloc (sizeof (fixS) * num_recs);
- memset (fixes, 0, sizeof (fixS) * num_recs);
-
- seginfo->fix_root = fixes;
- seginfo->fix_tail = &fixes[num_recs - 1];
+ subseg_set (sec, 0);
+ frag_data = frag_more (rec_size);
cur_block = block;
- frag_data = &fragP->fr_literal[0];
for (i = 0; i < num_recs; i++)
{
- fixS *fix = &fixes[i];
- assert (cur_block);
+ fixS *fix;
/* Write the fixup. */
- if (i != num_recs - 1)
- fix->fx_next = &fixes[i + 1];
- else
- fix->fx_next = NULL;
- fix->fx_size = 4;
- fix->fx_done = 0;
- fix->fx_frag = fragP;
- fix->fx_where = i * 8;
- fix->fx_addsy = section_symbol (cur_block->sec);
- fix->fx_offset = cur_block->offset;
- fix->fx_r_type = BFD_RELOC_32;
- fix->fx_file = "Internal Assembly";
+ gas_assert (cur_block);
+ fix = fix_new (frag_now, i * 8, 4,
+ section_symbol (cur_block->sec),
+ cur_block->offset,
+ false, BFD_RELOC_32);
+ fix->fx_file = "<internal>";
fix->fx_line = 0;
/* Write the length. */
- md_number_to_chars (&frag_data[4 + 8 * i],
+ md_number_to_chars (&frag_data[4 + i * 8],
cur_block->size, 4);
cur_block = cur_block->next;
}
+ frag_wane (frag_now);
+ frag_new (0);
+ frag_wane (frag_now);
}
}
}
seclist = &(*seclist)->next)
{
segT sec = *seclist;
- flagword flags;
- flags = bfd_get_section_flags (stdoutput, sec);
- if ((flags & SEC_DEBUGGING)
- || !(flags & SEC_ALLOC)
- || (flags & SEC_MERGE))
+ if (exclude_section_from_property_tables (sec))
continue;
if (section_has_xproperty (sec, flag_fn))
{
- segT insn_sec =
- xtensa_get_property_section (sec, section_name_base);
- segment_info_type *xt_seg_info = retrieve_segment_info (insn_sec);
- xtensa_block_info **xt_blocks =
- &xt_seg_info->tc_segment_info_data.blocks[sec_type];
+ segment_info_type *xt_seg_info;
+ xtensa_block_info **xt_blocks;
+ segT prop_sec = xtensa_make_property_section (sec, section_name_base);
+
+ prop_sec->output_section = prop_sec;
+ subseg_set (prop_sec, 0);
+ xt_seg_info = seg_info (prop_sec);
+ xt_blocks = &xt_seg_info->tc_segment_info_data.blocks[sec_type];
+
/* Walk over all of the frchains here and add new sections. */
- add_xt_prop_frags (sec, insn_sec, xt_blocks, flag_fn);
+ add_xt_prop_frags (sec, xt_blocks, flag_fn);
}
}
if (block)
{
xtensa_block_info *cur_block;
- /* This is a section with some data. */
int num_recs = 0;
bfd_size_type rec_size;
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; */
- /* In order to make this work with the assembler, we have to build
- some frags then build the "fixups" for it. It would be easier to
- just set the contents then set the arlents. */
-
if (num_recs)
{
- /* Allocate a fragment and (unfortunately) leak it. */
- fragS *fragP;
- bfd_size_type frag_size;
- fixS *fixes;
- frchainS *frchainP;
- int i;
char *frag_data;
+ int i;
- frag_size = sizeof (fragS) + rec_size;
- fragP = (fragS *) xmalloc (frag_size);
-
- memset (fragP, 0, frag_size);
- fragP->fr_address = 0;
- fragP->fr_next = NULL;
- fragP->fr_fix = rec_size;
- fragP->fr_var = 0;
- fragP->fr_type = rs_fill;
- /* The rest are zeros. */
-
- frchainP = seginfo->frchainP;
- frchainP->frch_root = fragP;
- frchainP->frch_last = fragP;
-
- fixes = (fixS *) xmalloc (sizeof (fixS) * num_recs);
- memset (fixes, 0, sizeof (fixS) * num_recs);
-
- seginfo->fix_root = fixes;
- seginfo->fix_tail = &fixes[num_recs - 1];
+ subseg_set (sec, 0);
+ frag_data = frag_more (rec_size);
cur_block = block;
- frag_data = &fragP->fr_literal[0];
for (i = 0; i < num_recs; i++)
{
- fixS *fix = &fixes[i];
- assert (cur_block);
+ fixS *fix;
/* Write the fixup. */
- if (i != num_recs - 1)
- fix->fx_next = &fixes[i + 1];
- else
- fix->fx_next = NULL;
- fix->fx_size = 4;
- fix->fx_done = 0;
- fix->fx_frag = fragP;
- fix->fx_where = i * (8 + 4);
- fix->fx_addsy = section_symbol (cur_block->sec);
- fix->fx_offset = cur_block->offset;
- fix->fx_r_type = BFD_RELOC_32;
- fix->fx_file = "Internal Assembly";
+ gas_assert (cur_block);
+ fix = fix_new (frag_now, i * 12, 4,
+ section_symbol (cur_block->sec),
+ cur_block->offset,
+ false, BFD_RELOC_32);
+ fix->fx_file = "<internal>";
fix->fx_line = 0;
/* Write the length. */
- md_number_to_chars (&frag_data[4 + (8+4) * i],
+ md_number_to_chars (&frag_data[4 + i * 12],
cur_block->size, 4);
- md_number_to_chars (&frag_data[8 + (8+4) * i],
+ md_number_to_chars (&frag_data[8 + i * 12],
frag_flags_to_number (&cur_block->flags),
- 4);
+ sizeof (flagword));
cur_block = cur_block->next;
}
+ frag_wane (frag_now);
+ frag_new (0);
+ frag_wane (frag_now);
}
}
}
}
-static segment_info_type *
-retrieve_segment_info (segT seg)
+static bool
+exclude_section_from_property_tables (segT sec)
{
- segment_info_type *seginfo;
- seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
- if (!seginfo)
- {
- frchainS *frchainP;
+ flagword flags = bfd_section_flags (sec);
- seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
- memset ((void *) seginfo, 0, sizeof (*seginfo));
- seginfo->fix_root = NULL;
- seginfo->fix_tail = NULL;
- seginfo->bfd_section = seg;
- seginfo->sym = 0;
- /* We will not be dealing with these, only our special ones. */
- bfd_set_section_userdata (stdoutput, seg, (void *) seginfo);
+ /* Sections that don't contribute to the memory footprint are excluded. */
+ if ((flags & SEC_DEBUGGING)
+ || !(flags & SEC_ALLOC)
+ || (flags & SEC_MERGE))
+ return true;
- frchainP = (frchainS *) xmalloc (sizeof (frchainS));
- frchainP->frch_root = NULL;
- frchainP->frch_last = NULL;
- frchainP->frch_next = NULL;
- frchainP->frch_subseg = 0;
- frchainP->fix_root = NULL;
- frchainP->fix_tail = NULL;
- /* Do not init the objstack. */
- /* obstack_begin (&frchainP->frch_obstack, chunksize); */
- /* frchainP->frch_frag_now = fragP; */
- frchainP->frch_frag_now = NULL;
-
- seginfo->frchainP = frchainP;
- }
+ /* 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 seginfo;
+ 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;
}
static void
add_xt_block_frags (segT sec,
- segT xt_block_sec,
xtensa_block_info **xt_block,
frag_predicate property_function,
frag_predicate end_property_function)
{
- segment_info_type *seg_info;
- segment_info_type *xt_seg_info;
- bfd_vma seg_offset;
fragS *fragP;
- xt_seg_info = retrieve_segment_info (xt_block_sec);
- seg_info = retrieve_segment_info (sec);
-
/* Build it if needed. */
while (*xt_block != NULL)
xt_block = &(*xt_block)->next;
/* We are either at NULL at the beginning or at the end. */
/* Walk through the frags. */
- seg_offset = 0;
-
- if (seg_info->frchainP)
+ if (seg_info (sec)->frchainP)
{
- for (fragP = seg_info->frchainP->frch_root;
+ for (fragP = seg_info (sec)->frchainP->frch_root;
fragP;
fragP = fragP->fr_next)
{
}
if (*xt_block == NULL)
{
- xtensa_block_info *new_block = (xtensa_block_info *)
- xmalloc (sizeof (xtensa_block_info));
+ xtensa_block_info *new_block = XNEW (xtensa_block_info);
new_block->sec = sec;
new_block->offset = fragP->fr_address;
new_block->size = fragP->fr_fix;
/* 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;
+ }
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_vma
+static flagword
frag_flags_to_number (const frag_flags *prop_flags)
{
- bfd_vma num = 0;
+ flagword num = 0;
if (prop_flags->is_literal)
num |= XTENSA_PROP_LITERAL;
if (prop_flags->is_insn)
}
-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;
}
static void
add_xt_prop_frags (segT sec,
- segT xt_block_sec,
xtensa_block_info **xt_block,
frag_flags_fn property_function)
{
- segment_info_type *seg_info;
- segment_info_type *xt_seg_info;
- bfd_vma seg_offset;
fragS *fragP;
- xt_seg_info = retrieve_segment_info (xt_block_sec);
- seg_info = retrieve_segment_info (sec);
/* Build it if needed. */
while (*xt_block != NULL)
{
/* We are either at NULL at the beginning or at the end. */
/* Walk through the frags. */
- seg_offset = 0;
-
- if (seg_info->frchainP)
+ if (seg_info (sec)->frchainP)
{
- for (fragP = seg_info->frchainP->frch_root; fragP;
+ for (fragP = seg_info (sec)->frchainP->frch_root; fragP;
fragP = fragP->fr_next)
{
xtensa_block_info tmp_block;
xtensa_block_info *new_block;
if ((*xt_block) != NULL)
xt_block = &(*xt_block)->next;
- new_block = (xtensa_block_info *)
- xmalloc (sizeof (xtensa_block_info));
+ new_block = XNEW (xtensa_block_info);
*new_block = tmp_block;
*xt_block = new_block;
}
int slot;
int num_opcodes = xtensa_isa_num_opcodes (isa);
- op_placement_table = (op_placement_info_table)
- xmalloc (sizeof (op_placement_info) * num_opcodes);
- assert (xtensa_isa_num_formats (isa) < MAX_FORMATS);
+ op_placement_table = XNEWVEC (op_placement_info, num_opcodes);
+ gas_assert (xtensa_isa_num_formats (isa) < MAX_FORMATS);
for (opcode = 0; opcode < num_opcodes; opcode++)
{
op_placement_info *opi = &op_placement_table[opcode];
/* FIXME: Make tinsn allocation dynamic. */
- if (xtensa_opcode_num_operands (isa, opcode) >= MAX_INSN_ARGS)
+ if (xtensa_opcode_num_operands (isa, opcode) > MAX_INSN_ARGS)
as_fatal (_("too many operands in instruction"));
opi->narrowest = XTENSA_UNDEFINED;
opi->narrowest_size = 0x7F;
}
-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]);
void
istack_init (IStack *stack)
{
- memset (stack, 0, sizeof (IStack));
stack->ninsn = 0;
}
-bfd_boolean
+bool
istack_empty (IStack *stack)
{
return (stack->ninsn == 0);
}
-bfd_boolean
+bool
istack_full (IStack *stack)
{
return (stack->ninsn == MAX_ISTACK);
istack_top (IStack *stack)
{
int rec = stack->ninsn - 1;
- assert (!istack_empty (stack));
+ gas_assert (!istack_empty (stack));
return &stack->insn[rec];
}
istack_push (IStack *stack, TInsn *insn)
{
int rec = stack->ninsn;
- assert (!istack_full (stack));
+ gas_assert (!istack_full (stack));
stack->insn[rec] = *insn;
stack->ninsn++;
}
{
int rec = stack->ninsn;
TInsn *insn;
- assert (!istack_full (stack));
+ gas_assert (!istack_full (stack));
insn = &stack->insn[rec];
tinsn_init (insn);
stack->ninsn++;
istack_pop (IStack *stack)
{
int rec = stack->ninsn - 1;
- assert (!istack_empty (stack));
+ gas_assert (!istack_empty (stack));
stack->ninsn--;
tinsn_init (&stack->insn[rec]);
}
/* 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;
int n = insn->ntok;
- assert (insn->insn_type == ITYPE_INSN);
+ gas_assert (insn->insn_type == ITYPE_INSN);
for (i = 0; i < n; ++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;
int i;
int n = insn->ntok;
- assert (insn->insn_type == ITYPE_INSN);
+ gas_assert (insn->insn_type == ITYPE_INSN);
for (i = 0; i < n; ++i)
{
&& 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;
int n = insn->ntok;
- assert (insn->insn_type == ITYPE_INSN);
+ gas_assert (insn->insn_type == ITYPE_INSN);
for (i = 0; i < n; ++i)
{
switch (insn->tok[i].X_op)
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;
- assert (tinsn->insn_type == ITYPE_INSN);
+ gas_assert (tinsn->insn_type == ITYPE_INSN);
if (noperands != tinsn->ntok)
as_fatal (_("operand number mismatch"));
{
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++)
{
- expressionS *expr = &tinsn->tok[i];
+ expressionS *exp = &tinsn->tok[i];
int rc;
unsigned line;
- char *file_name;
+ const char *file_name;
uint32 opnd_value;
- switch (expr->X_op)
+ switch (exp->X_op)
{
case O_register:
if (xtensa_operand_is_visible (isa, opcode, i) == 0)
break;
/* The register number has already been checked in
expression_maybe_register, so we don't need to check here. */
- opnd_value = expr->X_add_number;
+ opnd_value = exp->X_add_number;
(void) xtensa_operand_encode (isa, opcode, i, &opnd_value);
rc = xtensa_operand_set_field (isa, opcode, i, fmt, slot, slotbuf,
opnd_value);
case O_constant:
if (xtensa_operand_is_visible (isa, opcode, i) == 0)
break;
- as_where (&file_name, &line);
+ file_name = as_where (&line);
/* It is a constant and we called this function
then we have to try to fit it. */
xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode, i,
- expr->X_add_number, file_name, line);
+ exp->X_add_number, file_name, line);
break;
default:
- 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;
xtensa_opcode opcode = insn->opcode;
+ xtensa_regfile t1_regfile, t2_regfile;
+ int t1_reg, t2_reg;
+ int t1_base_reg, t1_last_reg;
+ int t2_base_reg, t2_last_reg;
+ char t1_inout, t2_inout;
+ int i, j;
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. */
+ for (j = 0; j < insn->ntok; j++)
+ {
+ if (xtensa_operand_is_register (isa, insn->opcode, j) != 1)
+ continue;
+
+ t2_regfile = xtensa_operand_regfile (isa, insn->opcode, j);
+ t2_base_reg = insn->tok[j].X_add_number;
+ t2_last_reg
+ = t2_base_reg + xtensa_operand_num_regs (isa, insn->opcode, j);
+
+ for (i = 0; i < insn->ntok; i++)
+ {
+ if (i == j)
+ continue;
+
+ if (xtensa_operand_is_register (isa, insn->opcode, i) != 1)
+ continue;
+
+ t1_regfile = xtensa_operand_regfile (isa, insn->opcode, i);
+
+ if (t1_regfile != t2_regfile)
+ continue;
+
+ t1_inout = xtensa_operand_inout (isa, insn->opcode, i);
+ t2_inout = xtensa_operand_inout (isa, insn->opcode, j);
+
+ t1_base_reg = insn->tok[i].X_add_number;
+ t1_last_reg = (t1_base_reg
+ + xtensa_operand_num_regs (isa, insn->opcode, i));
+
+ for (t1_reg = t1_base_reg; t1_reg < t1_last_reg; t1_reg++)
+ {
+ for (t2_reg = t2_base_reg; t2_reg < t2_last_reg; t2_reg++)
+ {
+ if (t1_reg != t2_reg)
+ continue;
+
+ if (t1_inout != 'i' && t2_inout != 'i')
+ {
+ as_bad (_("multiple writes to the same register"));
+ 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++)
if (fragP->tc_frag_data.slot_symbols[slot])
{
opnum = get_relaxable_immed (opcode);
- assert (opnum >= 0);
+ gas_assert (opnum >= 0);
set_expr_symbol_offset (&tinsn->tok[opnum],
fragP->tc_frag_data.slot_symbols[slot],
fragP->tc_frag_data.slot_offsets[slot]);
}
+ tinsn->extra_arg = fragP->tc_frag_data.free_reg[slot];
}
if (v->insnbuf == NULL)
as_fatal (_("out of memory"));
- for (i = 0; i < MAX_SLOTS; i++)
+ for (i = 0; i < config_max_slots; i++)
{
v->slotbuf[i] = xtensa_insnbuf_alloc (isa);
if (v->slotbuf[i] == NULL)
{
int i;
- memset (v, 0, offsetof (vliw_insn, insnbuf));
+ memset (v, 0, offsetof (vliw_insn, slots)
+ + sizeof(TInsn) * config_max_slots);
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;
- for (i = 0; i < MAX_SLOTS; i++)
+ for (i = 0; i < config_max_slots; i++)
v->slots[i].opcode = XTENSA_UNDEFINED;
}
-static bfd_boolean
+static void
+xg_copy_vinsn (vliw_insn *dst, vliw_insn *src)
+{
+ memcpy (dst, src,
+ offsetof(vliw_insn, slots) + src->num_slots * sizeof(TInsn));
+ dst->insnbuf = src->insnbuf;
+ memcpy (dst->slotbuf, src->slotbuf, src->num_slots * sizeof(xtensa_insnbuf));
+}
+
+
+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;
}
{
int i;
xtensa_insnbuf_free (xtensa_default_isa, v->insnbuf);
- for (i = 0; i < MAX_SLOTS; i++)
+ for (i = 0; i < config_max_slots; i++)
xtensa_insnbuf_free (xtensa_default_isa, v->slotbuf[i]);
}
/* 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);
for (slot = 0; slot < vinsn->num_slots; slot++)
{
TInsn *tinsn = &vinsn->slots[slot];
- bfd_boolean tinsn_has_fixup =
+ expressionS *extra_arg = &tinsn->extra_arg;
+ bool tinsn_has_fixup =
tinsn_to_slotbuf (vinsn->format, slot, tinsn,
vinsn->slotbuf[slot]);
xtensa_format_set_slot (isa, fmt, slot,
insnbuf, vinsn->slotbuf[slot]);
+ if (extra_arg->X_op != O_illegal && extra_arg->X_op != O_register)
+ {
+ if (vinsn->num_slots != 1)
+ as_bad (_("TLS relocation not allowed in FLIX bundle"));
+ else if (record_fixup)
+ /* Instructions that generate TLS relocations should always be
+ relaxed in the front-end. If "record_fixup" is set, then this
+ function is being called during back-end relaxation, so flag
+ the unexpected behavior as an error. */
+ as_bad (_("unexpected TLS relocation"));
+ else
+ 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));
+ }
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++)
{
- expressionS* expr = &tinsn->tok[i];
- switch (expr->X_op)
+ expressionS* exp = &tinsn->tok[i];
+ switch (exp->X_op)
{
case O_symbol:
case O_lo16:
|| tinsn->is_specific_opcode
|| !xg_is_relaxable_insn (tinsn, 0))
{
- xg_add_opcode_fix (tinsn, i, fmt, slot, expr, fragP,
+ xg_add_opcode_fix (tinsn, i, fmt, slot, exp, fragP,
frag_offset - fragP->fr_literal);
}
else
{
- if (expr->X_op != O_symbol)
+ if (exp->X_op != O_symbol)
as_bad (_("invalid operand"));
- tinsn->symbol = expr->X_add_symbol;
- tinsn->offset = expr->X_add_number;
+ tinsn->symbol = exp->X_add_symbol;
+ tinsn->offset = exp->X_add_number;
}
}
else
/* Return TRUE if the expression is an integer constant. */
-bfd_boolean
+bool
expr_is_const (const expressionS *s)
{
return (s->X_op == O_constant);
offsetT
get_expr_const (const expressionS *s)
{
- assert (expr_is_const (s));
+ gas_assert (expr_is_const (s));
return s->X_add_number;
}
}
-bfd_boolean
+bool
expr_is_register (const expressionS *s)
{
return (s->X_op == O_register);
offsetT
get_expr_register (const expressionS *s)
{
- assert (expr_is_register (s));
+ gas_assert (expr_is_register (s));
return s->X_add_number;
}
/* 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;
}
struct rename_section_struct
{
- char *old_name;
+ const char *old_name;
char *new_name;
struct rename_section_struct *next;
};
}
/* Now add it. */
- r = (struct rename_section_struct *)
- xmalloc (sizeof (struct rename_section_struct));
+ r = XNEW (struct rename_section_struct);
r->old_name = xstrdup (old_name);
r->new_name = xstrdup (new_name);
r->next = section_rename;
char *
-xtensa_section_rename (char *name)
+xtensa_section_rename (const char *name)
{
struct rename_section_struct *r = section_rename;
return r->new_name;
}
- return name;
+ return (char *) name;
}