]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-xtensa.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gas / config / tc-xtensa.c
index 3b551c4e583ec6bfc52e38908ffc97a4df004ada..3e3deb5dd3654b67d916fec4ea3e26c38f839489 100644 (file)
@@ -1,11 +1,11 @@
 /* tc-xtensa.c -- Assemble Xtensa instructions.
-   Copyright 2003, 2004, 2005 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 <string.h>
-#include <limits.h>
 #include "as.h"
+#include <limits.h>
 #include "sb.h"
 #include "safe-ctype.h"
 #include "tc-xtensa.h"
-#include "frags.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 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
 #define uint32 unsigned int
@@ -68,22 +79,22 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 /* 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
@@ -97,33 +108,32 @@ static bfd_boolean past_xtensa_end = FALSE;
 
 #define LITERAL_SECTION_NAME           xtensa_section_rename (".literal")
 #define LIT4_SECTION_NAME              xtensa_section_rename (".lit4")
-#define FINI_SECTION_NAME              xtensa_section_rename (".fini")
 #define INIT_SECTION_NAME              xtensa_section_rename (".init")
-#define FINI_LITERAL_SECTION_NAME      xtensa_section_rename (".fini.literal")
-#define INIT_LITERAL_SECTION_NAME      xtensa_section_rename (".init.literal")
+#define FINI_SECTION_NAME              xtensa_section_rename (".fini")
 
 
 /* This type is used for the directive_stack to keep track of the
-   state of the literal collection pools.  */
+   state of the literal collection pools.  If lit_prefix is set, it is
+   used to determine the literal section names; otherwise, the literal
+   sections are determined based on the current text section.  The
+   lit_seg and lit4_seg fields cache these literal sections, with the
+   current_text_seg field used a tag to indicate whether the cached
+   values are valid.  */
 
 typedef struct lit_state_struct
 {
-  const char *lit_seg_name;
-  const char *lit4_seg_name;
-  const char *init_lit_seg_name;
-  const char *fini_lit_seg_name;
+  char *lit_prefix;
+  segT current_text_seg;
   segT lit_seg;
   segT lit4_seg;
-  segT init_lit_seg;
-  segT fini_lit_seg;
 } lit_state;
 
 static lit_state default_lit_sections;
 
 
-/* We keep lists of literal segments.  The seg_list type is the node
-   for such a list.  The *_literal_head locals are the heads of the
-   various lists.  All of these lists have a dummy node at the start.  */
+/* We keep a list of literal segments.  The seg_list type is the node
+   for this list.  The literal_head pointer is the head of the list,
+   with the literal_head_h dummy node at the start.  */
 
 typedef struct seg_list_struct
 {
@@ -133,10 +143,6 @@ typedef struct seg_list_struct
 
 static seg_list literal_head_h;
 static seg_list *literal_head = &literal_head_h;
-static seg_list init_literal_head_h;
-static seg_list *init_literal_head = &init_literal_head_h;
-static seg_list fini_literal_head_h;
-static seg_list *fini_literal_head = &fini_literal_head_h;
 
 
 /* Lists of symbols.  We keep a list of symbols that label the current
@@ -189,7 +195,9 @@ int generating_literals = 0;
 /* Instruction only properties about code.  */
 #define XTENSA_PROP_INSN_NO_DENSITY    0x00000040
 #define XTENSA_PROP_INSN_NO_REORDER    0x00000080
-#define XTENSA_PROP_INSN_NO_TRANSFORM  0x00000100
+/* Historically, NO_TRANSFORM was a property of instructions,
+   but it should apply to literals under certain circumstances.  */
+#define XTENSA_PROP_NO_TRANSFORM       0x00000100
 
 /*  Branch target alignment information.  This transmits information
     to the linker optimization about the priority of aligning a
@@ -215,8 +223,6 @@ int generating_literals = 0;
 /* 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))
@@ -237,8 +243,6 @@ int generating_literals = 0;
 
 #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))
@@ -265,6 +269,9 @@ struct frag_flags_struct
   unsigned is_data : 1;
   unsigned is_unreachable : 1;
 
+  /* is_specific_opcode implies no_transform.  */
+  unsigned is_no_transform : 1;
+
   struct
   {
     unsigned is_loop_target : 1;
@@ -273,8 +280,6 @@ struct frag_flags_struct
 
     unsigned is_no_density : 1;
     /* no_longcalls flag does not need to be placed in the object file.  */
-    /* is_specific_opcode implies no_transform.  */
-    unsigned is_no_transform : 1;
 
     unsigned is_no_reorder : 1;
 
@@ -327,15 +332,9 @@ typedef struct op_placement_info_struct
      restrictive is the opcode that fits only one slot in one
      format.  */
   int issuef;
-  /* The single format (i.e., if the op can live in a bundle by itself),
-     narrowest format, and widest format the op can be bundled in
-     and their sizes:  */
-  xtensa_format single;
   xtensa_format narrowest;
-  xtensa_format widest;
   char narrowest_size;
-  char widest_size;
-  char single_size;
+  char narrowest_slot;
 
   /* formats is a bitfield with the Nth bit set
      if the opcode fits in the Nth xtensa_format.  */
@@ -359,6 +358,35 @@ op_placement_info_table op_placement_table;
 #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
+{
+  const char *suffix;
+  int length;
+  bfd_reloc_code_real_type reloc;
+  operatorT operator;
+};
+
+#define SUFFIX_MAP(str, reloc, op) { str, sizeof (str) - 1, reloc, op }
+
+static struct suffix_reloc_map suffix_relocs[] =
+{
+  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),
+  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),
+};
 
 
 /* Directives.  */
@@ -380,54 +408,78 @@ typedef enum
 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 }
+};
+
+bool directive_state[] =
+{
+  false,                       /* none */
+  false,                       /* literal */
+  false,                       /* density */
+  true,                                /* transform */
+  false,                       /* freeregs */
+  false,                       /* longcalls */
+  false,                       /* literal_prefix */
+  false,                       /* schedule */
+  false                                /* absolute_literals */
 };
 
-bfd_boolean directive_state[] =
+/* 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 */
-  TRUE,                                /* 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_begin_directive (int);
 static void xtensa_end_directive (int);
-static void xtensa_dwarf2_directive_loc (int);
-static void xtensa_literal_prefix (char const *, int);
+static void xtensa_literal_prefix (void);
 static void xtensa_literal_position (int);
 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.  */
 
@@ -435,21 +487,32 @@ static bfd_reloc_code_real_type xtensa_elf_suffix (char **, expressionS *);
 
 /* 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().  */
@@ -459,7 +522,7 @@ static long relax_frag_add_nop (fragS *);
 /* 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);
@@ -472,53 +535,49 @@ static void xtensa_switch_to_literal_fragment (emit_state *);
 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 void cache_literal_section
-  (seg_list *, const char *, segT *, bfd_boolean);
-
-/* Import from elf32-xtensa.c in BFD library.  */
-
-extern char *xtensa_get_property_section_name (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);
-static void set_expr_symbol_offset_diff
-  (expressionS *, symbolS *, symbolS *, offsetT);
-bfd_boolean expr_is_equal (expressionS *, expressionS *);
+bool expr_is_equal (expressionS *, expressionS *);
 static void copy_expr (expressionS *, const expressionS *);
 
 /* Section renaming.  */
@@ -543,9 +602,11 @@ static xtensa_opcode xtensa_callx8_opcode;
 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;
@@ -560,20 +621,24 @@ static xtensa_opcode xtensa_retw_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;
+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
@@ -581,8 +646,15 @@ static bfd_boolean maybe_has_close_loop_end = FALSE;
    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)
@@ -593,11 +665,12 @@ 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;
+      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;
     }
 }
 
@@ -607,6 +680,10 @@ enum
   option_density = OPTION_MD_BASE,
   option_no_density,
 
+  option_flix,
+  option_no_generate_flix,
+  option_no_flix,
+
   option_relax,
   option_no_relax,
 
@@ -655,7 +732,20 @@ enum
   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 = "";
@@ -665,6 +755,10 @@ struct option md_longopts[] =
   { "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 },
@@ -724,6 +818,18 @@ struct option md_longopts[] =
 
   { "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 }
 };
 
@@ -731,7 +837,7 @@ size_t md_longopts_size = sizeof md_longopts;
 
 
 int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
 {
   switch (c)
     {
@@ -742,10 +848,19 @@ md_parse_option (int c, char *arg)
       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"));
@@ -760,16 +875,16 @@ md_parse_option (int c, char *arg)
       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)
@@ -777,63 +892,63 @@ md_parse_option (int c, char *arg)
          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:
@@ -860,20 +975,21 @@ md_parse_option (int c, char *arg)
     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);
@@ -892,7 +1008,62 @@ md_parse_option (int c, char *arg)
         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:
@@ -913,7 +1084,23 @@ Xtensa options:\n\
   --[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
@@ -925,7 +1112,7 @@ xtensa_add_insn_label (symbolS *sym)
   sym_list *l;
 
   if (!free_insn_labels)
-    l = (sym_list *) xmalloc (sizeof (sym_list));
+    l = XNEW (sym_list);
   else
     {
       l = free_insn_labels;
@@ -950,43 +1137,16 @@ xtensa_clear_insn_labels (void)
 }
 
 
-/* The "loops_ok" argument is provided to allow ignoring labels that
-   define loop ends.  This fixes a bug where the NOPs to align a
-   loop opcode were included in a previous zero-cost loop:
-
-   loop a0, loopend
-     <loop1 body>
-   loopend:
-
-   loop a2, loopend2
-     <loop2 body>
-
-   would become:
-
-   loop a0, loopend
-     <loop1 body>
-     nop.n <===== bad!
-   loopend:
-
-   loop a2, loopend2
-     <loop2 body>
-
-   This argument is used to prevent moving the NOP to before the
-   loop-end label, which is what you want in this special case.  */
-
 static void
-xtensa_move_labels (fragS *new_frag, valueT new_offset, bfd_boolean loops_ok)
+xtensa_move_labels (fragS *new_frag, valueT new_offset)
 {
   sym_list *lit;
 
   for (lit = insn_labels; lit; lit = lit->next)
     {
       symbolS *lit_sym = lit->sym;
-      if (loops_ok || ! symbol_get_tc (lit_sym)->is_loop_target)
-       {
-         S_SET_VALUE (lit_sym, new_offset);
-         symbol_set_frag (lit_sym, new_frag);
-       }
+      S_SET_VALUE (lit_sym, new_offset);
+      symbol_set_frag (lit_sym, new_frag);
     }
 }
 
@@ -996,8 +1156,8 @@ xtensa_move_labels (fragS *new_frag, valueT new_offset, bfd_boolean loops_ok)
 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;
@@ -1013,45 +1173,48 @@ const pseudo_typeS md_pseudo_table[] =
   { "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 },
-  { "loc", xtensa_dwarf2_directive_loc, 0 },
   { "literal", xtensa_literal_pseudo, 0 },
   { "frequency", xtensa_frequency_pseudo, 0 },
   { NULL, 0, 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;
@@ -1068,7 +1231,7 @@ directive_push (directiveE directive, bfd_boolean negated, const void *datum)
 
 static void
 directive_pop (directiveE *directive,
-              bfd_boolean *negated,
+              bool *negated,
               const char **file,
               unsigned int *line,
               const void **datum)
@@ -1077,7 +1240,7 @@ directive_pop (directiveE *directive,
 
   if (!directive_state_stack)
     {
-      as_bad (_("unmatched end directive"));
+      as_bad (_("unmatched .end directive"));
       *directive = directive_none;
       return;
     }
@@ -1099,7 +1262,7 @@ directive_balance (void)
   while (directive_state_stack)
     {
       directiveE directive;
-      bfd_boolean negated;
+      bool negated;
       const char *file;
       unsigned int line;
       const void *datum;
@@ -1111,7 +1274,7 @@ directive_balance (void)
 }
 
 
-static bfd_boolean
+static bool
 inside_directive (directiveE dir)
 {
   state_stackS *top = directive_state_stack;
@@ -1124,17 +1287,17 @@ inside_directive (directiveE dir)
 
 
 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;
     }
 
@@ -1145,12 +1308,12 @@ get_directive (directiveE *directive, bfd_boolean *negated)
      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";
@@ -1180,9 +1343,8 @@ static void
 xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED)
 {
   directiveE directive;
-  bfd_boolean negated;
+  bool negated;
   emit_state *state;
-  int len;
   lit_state *ls;
 
   get_directive (&directive, &negated);
@@ -1206,7 +1368,7 @@ xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED)
          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;
@@ -1225,24 +1387,14 @@ xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED)
 
       /* 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);
 
-      /* Parse the new prefix from the input_line_pointer.  */
-      SKIP_WHITESPACE ();
-      len = strspn (input_line_pointer,
-                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                   "abcdefghijklmnopqrstuvwxyz_/0123456789.$");
-
       /* Process the new prefix.  */
-      xtensa_literal_prefix (input_line_pointer, len);
-
-      /* Skip the name in the input line.  */
-      input_line_pointer += len;
+      xtensa_literal_prefix ();
       break;
 
     case directive_freeregs:
@@ -1291,7 +1443,7 @@ static void
 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;
@@ -1305,18 +1457,18 @@ xtensa_end_directive (int ignore ATTRIBUTE_UNUSED)
 
   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"));
@@ -1361,12 +1513,11 @@ xtensa_end_directive (int ignore ATTRIBUTE_UNUSED)
            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;
 
-             if (use_literal_section)
-               default_lit_sections = *s;
-
-             /* free the state storage */
+             /* Free the state storage.  */
+             free (s->lit_prefix);
              free (s);
              break;
 
@@ -1385,28 +1536,6 @@ xtensa_end_directive (int ignore ATTRIBUTE_UNUSED)
 }
 
 
-/* Wrap dwarf2 functions so that we correctly support the .loc directive.  */
-
-static bfd_boolean xtensa_loc_directive_seen = FALSE;
-
-static void
-xtensa_dwarf2_directive_loc (int x)
-{
-  xtensa_loc_directive_seen = TRUE;
-  dwarf2_directive_loc (x);
-}
-
-
-static void
-xtensa_dwarf2_emit_insn (int size, struct dwarf2_line_info *loc)
-{
-  if (debug_type != DEBUG_DWARF2 && ! xtensa_loc_directive_seen)
-    return;
-  xtensa_loc_directive_seen = FALSE;
-  dwarf2_gen_line_info (frag_now_fix () - size, loc);
-}
-
-
 /* Place an aligned literal fragment at the current location.  */
 
 static void
@@ -1431,7 +1560,6 @@ xtensa_literal_pseudo (int ignored ATTRIBUTE_UNUSED)
   emit_state state;
   char *p, *base_name;
   char c;
-  segT dest_seg;
 
   if (inside_directive (directive_literal))
     {
@@ -1447,27 +1575,19 @@ xtensa_literal_pseudo (int ignored ATTRIBUTE_UNUSED)
   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 != ':')
     {
@@ -1477,11 +1597,11 @@ xtensa_literal_pseudo (int ignored ATTRIBUTE_UNUSED)
       xtensa_restore_emit_state (&state);
       return;
     }
-  *p = 0;
 
+  *p = 0;
   colon (base_name);
-
   *p = c;
+
   input_line_pointer++;                /* skip ',' or ':' */
 
   xtensa_elf_cons (4);
@@ -1495,62 +1615,28 @@ xtensa_literal_pseudo (int ignored ATTRIBUTE_UNUSED)
 
 
 static void
-xtensa_literal_prefix (char const *start, int len)
+xtensa_literal_prefix (void)
 {
-  char *name, *linkonce_suffix;
-  char *newname, *newname4;
-  size_t linkonce_len;
-
-  /* Get a null-terminated copy of the name.  */
-  name = xmalloc (len + 1);
-  assert (name);
-
-  strncpy (name, start, len);
-  name[len] = 0;
-
-  /* Allocate the sections (interesting note: the memory pointing to
-     the name is actually used for the name by the new section). */
-
-  newname = xmalloc (len + strlen (".literal") + 1);
-  newname4 = xmalloc (len + strlen (".lit4") + 1);
-
-  linkonce_len = sizeof (".gnu.linkonce.") - 1;
-  if (strncmp (name, ".gnu.linkonce.", linkonce_len) == 0
-      && (linkonce_suffix = strchr (name + linkonce_len, '.')) != 0)
-    {
-      strcpy (newname, ".gnu.linkonce.literal");
-      strcpy (newname4, ".gnu.linkonce.lit4");
+  char *name;
+  int len;
 
-      strcat (newname, linkonce_suffix);
-      strcat (newname4, linkonce_suffix);
-    }
-  else
-    {
-      int suffix_pos = len;
+  /* Parse the new prefix from the input_line_pointer.  */
+  SKIP_WHITESPACE ();
+  len = strspn (input_line_pointer,
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+               "abcdefghijklmnopqrstuvwxyz_/0123456789.$");
 
-      /* If the section name ends with ".text", then replace that suffix
-        instead of appending an additional suffix.  */
-      if (len >= 5 && strcmp (name + len - 5, ".text") == 0)
-       suffix_pos -= 5;
+  /* Get a null-terminated copy of the name.  */
+  name = xmemdup0 (input_line_pointer, len);
 
-      strcpy (newname, name);
-      strcpy (newname4, name);
+  /* Skip the name in the input line.  */
+  input_line_pointer += len;
 
-      strcpy (newname + suffix_pos, ".literal");
-      strcpy (newname4 + suffix_pos, ".lit4");
-    }
+  default_lit_sections.lit_prefix = name;
 
-  /* Note that cache_literal_section does not create a segment if
-     it already exists.  */
+  /* Clear cached literal sections, since the prefix has changed.  */
   default_lit_sections.lit_seg = NULL;
   default_lit_sections.lit4_seg = NULL;
-
-  /* Canonicalizing section names allows renaming literal
-     sections to occur correctly.  */
-  default_lit_sections.lit_seg_name = tc_canonicalize_symbol_name (newname);
-  default_lit_sections.lit4_seg_name = tc_canonicalize_symbol_name (newname4);
-
-  free (name);
 }
 
 
@@ -1623,18 +1709,27 @@ xtensa_elf_cons (int nbytes)
            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++ == ',');
 
@@ -1642,6 +1737,16 @@ xtensa_elf_cons (int nbytes)
   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.  */
 
@@ -1649,29 +1754,12 @@ xtensa_elf_cons (int nbytes)
 static bfd_reloc_code_real_type
 xtensa_elf_suffix (char **str_p, expressionS *exp_p)
 {
-  struct map_bfd
-  {
-    char *string;
-    int length;
-    bfd_reloc_code_real_type reloc;
-  };
-
   char ident[20];
   char *str = *str_p;
   char *str2;
   int ch;
   int len;
-  struct map_bfd *ptr;
-
-#define MAP(str,reloc) { str, sizeof (str) - 1, reloc }
-
-  static struct map_bfd mapping[] =
-  {
-    MAP ("l",          BFD_RELOC_LO16),
-    MAP ("h",          BFD_RELOC_HI16),
-    MAP ("plt",                BFD_RELOC_XTENSA_PLT),
-    { (char *) 0, 0,   BFD_RELOC_UNUSED }
-  };
+  unsigned int i;
 
   if (*str++ != '@')
     return BFD_RELOC_NONE;
@@ -1688,10 +1776,10 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p)
   len = str2 - ident;
 
   ch = ident[0];
-  for (ptr = &mapping[0]; ptr->length > 0; ptr++)
-    if (ch == ptr->string[0]
-       && len == ptr->length
-       && memcmp (ident, ptr->string, 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 == '+')
@@ -1712,13 +1800,64 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p)
          }
 
        *str_p = str;
-       return ptr->reloc;
+       return suffix_relocs[i].reloc;
       }
 
   return BFD_RELOC_UNUSED;
 }
 
 
+/* Find the matching operator type.  */
+static operatorT
+map_suffix_reloc_to_operator (bfd_reloc_code_real_type reloc)
+{
+  operatorT operator = O_illegal;
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++)
+    {
+      if (suffix_relocs[i].reloc == reloc)
+       {
+         operator = suffix_relocs[i].operator;
+         break;
+       }
+    }
+  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, bool is_literal)
+{
+  unsigned int i;
+  bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
+
+  for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++)
+    {
+      if (suffix_relocs[i].operator == operator)
+       {
+         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;
+
+  return reloc;
+}
+
+
 static const char *
 expression_end (const char *name)
 {
@@ -1810,43 +1949,45 @@ expression_maybe_register (xtensa_opcode opc, int opnd, expressionS *tok)
     {
       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;
        }
 
       if ((tok->X_op == O_constant || tok->X_op == O_symbol)
-         && (reloc = xtensa_elf_suffix (&input_line_pointer, tok))
-         && (reloc != BFD_RELOC_NONE))
+         && ((reloc = xtensa_elf_suffix (&input_line_pointer, tok))
+             != BFD_RELOC_NONE))
        {
          switch (reloc)
            {
-             default:
-             case BFD_RELOC_UNUSED:
-               as_bad (_("unsupported relocation"));
-               break;
-
-             case BFD_RELOC_XTENSA_PLT:
-               tok->X_op = O_pltrel;
-               break;
-
-             case BFD_RELOC_LO16:
-               if (tok->X_op == O_constant)
+           case BFD_RELOC_LO16:
+             if (tok->X_op == O_constant)
+               {
                  tok->X_add_number &= 0xffff;
-               else
-                 tok->X_op = O_lo16;
-               break;
-
-             case BFD_RELOC_HI16:
-               if (tok->X_op == O_constant)
+                 return;
+               }
+             break;
+           case BFD_RELOC_HI16:
+             if (tok->X_op == O_constant)
+               {
                  tok->X_add_number = ((unsigned) tok->X_add_number) >> 16;
-               else
-                 tok->X_op = O_hi16;
-               break;
+                 return;
+               }
+             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);
        }
     }
   else
@@ -1874,9 +2015,9 @@ static int
 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;
@@ -1898,14 +2039,14 @@ tokenize_arguments (char **args, char *str)
          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:
@@ -1917,7 +2058,7 @@ tokenize_arguments (char **args, char *str)
            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)
@@ -1927,20 +2068,20 @@ tokenize_arguments (char **args, char *str)
 
          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)
@@ -1956,12 +2097,12 @@ err:
 
 /* 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;
@@ -2000,7 +2141,7 @@ parse_arguments (TInsn *insn, int num_args, char **arg_strings)
          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
@@ -2015,7 +2156,7 @@ parse_arguments (TInsn *insn, int num_args, char **arg_strings)
              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;
@@ -2032,6 +2173,7 @@ parse_arguments (TInsn *insn, int num_args, char **arg_strings)
 
          last_tok = tok;
          last_opnd_cnt = opnd_cnt;
+         demand_empty_rest_of_line ();
 
          do
            {
@@ -2046,7 +2188,7 @@ parse_arguments (TInsn *insn, int num_args, char **arg_strings)
     goto err;
 
   insn->ntok = tok - insn->tok;
-  had_error = FALSE;
+  had_error = false;
 
  err:
   input_line_pointer = old_input_line_pointer;
@@ -2129,8 +2271,7 @@ xg_reverse_shift_count (char **cnt_argp)
   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;
@@ -2161,11 +2302,10 @@ xg_arg_is_constant (char *arg, offsetT *valp)
 
 
 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);
 }
 
 
@@ -2212,14 +2352,10 @@ xg_translate_sysreg_op (char **popname, int *pnum_args, char **arg_strings)
   char *opname, *new_opname;
   const char *sr_name;
   int is_user, is_write;
-  bfd_boolean has_underbar = FALSE;
 
   opname = *popname;
   if (*opname == '_')
-    {
-      has_underbar = TRUE;
-      opname += 1;
-    }
+    opname += 1;
   is_user = (opname[1] == 'u');
   is_write = (opname[0] == 'w');
 
@@ -2264,9 +2400,7 @@ xg_translate_sysreg_op (char **popname, int *pnum_args, char **arg_strings)
   /* 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.%s", (has_underbar ? "_" : ""),
-          *popname, sr_name);
+  new_opname = concat (*popname, ".", sr_name, (char *) NULL);
   free (*popname);
   *popname = new_opname;
 
@@ -2281,12 +2415,12 @@ xtensa_translate_old_userreg_ops (char **popname)
   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;
     }
 
@@ -2325,7 +2459,7 @@ xtensa_translate_old_userreg_ops (char **popname)
 
   /* 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);
@@ -2336,8 +2470,8 @@ xtensa_translate_old_userreg_ops (char **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)
@@ -2346,7 +2480,7 @@ xtensa_translate_zero_immed (char *old_op,
   offsetT val;
 
   opname = *popname;
-  assert (opname[0] != '_');
+  gas_assert (opname[0] != '_');
 
   if (strcmp (opname, old_op) != 0)
     return 0;
@@ -2373,14 +2507,11 @@ static int
 xg_translate_idioms (char **popname, int *pnum_args, char **arg_strings)
 {
   char *opname = *popname;
-  bfd_boolean has_underbar = FALSE;
-
-  if (cur_vinsn.inside_bundle)
-    return 0;
+  bool has_underbar = false;
 
   if (*opname == '_')
     {
-      has_underbar = TRUE;
+      has_underbar = true;
       opname += 1;
     }
 
@@ -2393,13 +2524,24 @@ xg_translate_idioms (char **popname, int *pnum_args, char **arg_strings)
          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))
@@ -2420,7 +2562,11 @@ xg_translate_idioms (char **popname, int *pnum_args, char **arg_strings)
       return 0;
     }
 
-  if (xtensa_nop_opcode == XTENSA_UNDEFINED
+  /* Don't do anything special with NOPs inside FLIX instructions.  They
+     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
       && strcmp (opname, "nop") == 0)
     {
       if (use_transform () && !has_underbar && density_supported)
@@ -2430,12 +2576,9 @@ xg_translate_idioms (char **popname, int *pnum_args, char **arg_strings)
          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;
@@ -2618,23 +2761,23 @@ print_vliw_insn (xtensa_insnbuf vbuf)
 #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) == 0)
-    return FALSE;
+  if (xtensa_opcode_is_call (isa, opcode) != 1)
+    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;
 }
 
 
@@ -2642,19 +2785,19 @@ is_direct_call_opcode (xtensa_opcode opcode)
    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;
@@ -2707,7 +2850,7 @@ xtensa_insnbuf_set_operand (xtensa_insnbuf slotbuf,
       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);
@@ -2744,21 +2887,20 @@ xtensa_insnbuf_get_operand (xtensa_insnbuf slotbuf,
 
 /* 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'"),
@@ -2767,7 +2909,7 @@ xg_instruction_matches_option_term (TInsn *insn ATTRIBUTE_UNUSED,
 }
 
 
-static bfd_boolean
+static bool
 xg_instruction_matches_or_options (TInsn *insn,
                                   const ReqOrOptionList *or_option)
 {
@@ -2776,13 +2918,13 @@ xg_instruction_matches_or_options (TInsn *insn,
   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;
@@ -2794,21 +2936,21 @@ xg_instruction_matches_options (TInsn *insn, const ReqOptionList *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;
@@ -2822,7 +2964,7 @@ xg_instruction_matches_rule (TInsn *insn, TransitionRule *rule)
        {
        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))
            {
@@ -2830,14 +2972,14 @@ xg_instruction_matches_rule (TInsn *insn, TransitionRule *rule)
                {
                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))
@@ -2846,23 +2988,23 @@ xg_instruction_matches_rule (TInsn *insn, TransitionRule *rule)
                {
                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];
 
@@ -2870,11 +3012,11 @@ xg_instruction_matches_rule (TInsn *insn, TransitionRule *rule)
            {
            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;
@@ -2882,21 +3024,21 @@ xg_instruction_matches_rule (TInsn *insn, TransitionRule *rule)
        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;
@@ -2919,17 +3061,17 @@ transition_rule_cmp (const TransitionRule *a, const TransitionRule *b)
                  && 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;
@@ -2964,7 +3106,7 @@ xg_instruction_match (TInsn *insn)
 {
   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)
@@ -2979,14 +3121,14 @@ xg_instruction_match (TInsn *insn)
 \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;
 }
 
 
@@ -3000,15 +3142,15 @@ is_unique_insn_expansion (TransitionRule *r)
    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)
     {
@@ -3020,16 +3162,16 @@ xg_is_single_relaxable_insn (TInsn *insn, TInsn *targ, bfd_boolean narrow_only)
              <= 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;
 }
 
 
@@ -3042,7 +3184,7 @@ xg_get_max_insn_widen_size (xtensa_opcode opcode)
   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)
     {
@@ -3055,7 +3197,7 @@ xg_get_max_insn_widen_size (xtensa_opcode opcode)
       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
@@ -3088,7 +3230,7 @@ xg_get_max_insn_widen_literal_size (xtensa_opcode opcode)
   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)
     {
@@ -3101,7 +3243,7 @@ xg_get_max_insn_widen_literal_size (xtensa_opcode opcode)
       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
@@ -3126,15 +3268,15 @@ xg_get_max_insn_widen_literal_size (xtensa_opcode opcode)
 }
 
 
-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)
     {
@@ -3143,11 +3285,11 @@ xg_is_relaxable_insn (TInsn *insn, int lateral_steps)
       if (xg_instruction_matches_rule (insn, rule))
        {
          if (steps_taken == lateral_steps)
-           return TRUE;
+           return true;
          steps_taken++;
        }
     }
-  return FALSE;
+  return false;
 }
 
 
@@ -3173,7 +3315,7 @@ get_special_label_symbol (void)
 }
 
 
-static bfd_boolean
+static bool
 xg_valid_literal_expression (const expressionS *exp)
 {
   switch (exp->X_op)
@@ -3184,9 +3326,14 @@ xg_valid_literal_expression (const expressionS *exp)
     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;
     }
 }
 
@@ -3194,55 +3341,56 @@ xg_valid_literal_expression (const expressionS *exp)
 /* 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,
@@ -3257,27 +3405,28 @@ xg_symbolic_immeds_fit (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)
     {
-      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:
@@ -3285,29 +3434,31 @@ xg_symbolic_immeds_fit (const TInsn *insn,
             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
@@ -3326,43 +3477,44 @@ xg_symbolic_immeds_fit (const TInsn *insn,
          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;
 
-  memset (targ, 0, sizeof (TInsn));
-  targ->loc = insn->loc;
+  tinsn_init (targ);
+  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;
@@ -3373,12 +3525,20 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
              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 ();
@@ -3386,7 +3546,7 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
              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;
@@ -3401,8 +3561,8 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
                  /* 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)
@@ -3412,7 +3572,7 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
                      else if (op->typ == OP_OPERAND_LOW16U)
                        targ->tok[op_num].X_op = O_lo16;
                      else
-                       return FALSE;
+                       return false;
                    }
                }
              break;
@@ -3423,7 +3583,7 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
                 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;
@@ -3434,10 +3594,10 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
                      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;
            }
        }
@@ -3447,12 +3607,12 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
       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;
@@ -3460,17 +3620,17 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
          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;
            }
        }
@@ -3480,22 +3640,22 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
       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)
@@ -3503,15 +3663,15 @@ xg_build_to_stack (IStack *istack, TInsn *insn, BuildInstr *bi)
       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;
@@ -3519,8 +3679,8 @@ xg_expand_to_stack (IStack *istack, TInsn *insn, int lateral_steps)
   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)
     {
@@ -3534,32 +3694,58 @@ xg_expand_to_stack (IStack *istack, TInsn *insn, int lateral_steps)
 
              /* 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,
@@ -3572,12 +3758,9 @@ 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;
@@ -3593,12 +3776,12 @@ xg_assembly_relax (IStack *istack,
   current_insn = *insn;
 
   /* Walk through all of the single instruction expansions.  */
-  while (xg_is_single_relaxable_insn (&current_insn, &single_target, FALSE))
+  while (xg_is_single_relaxable_insn (&current_insn, &single_target, false))
     {
+      steps_taken++;
       if (xg_symbolic_immeds_fit (&single_target, pc_seg, pc_frag, pc_offset,
                                  stretch))
        {
-         steps_taken++;
          if (steps_taken >= min_steps)
            {
              istack_push (istack, &single_target);
@@ -3636,22 +3819,12 @@ xg_assembly_relax (IStack *istack,
 }
 
 
-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
@@ -3660,13 +3833,12 @@ xg_finish_frag (char *last_insn,
 
   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);
@@ -3675,37 +3847,37 @@ xg_finish_frag (char *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;
@@ -3715,9 +3887,9 @@ is_branch_jmp_to_next (TInsn *insn, fragS *fragP)
   symbolS *sym;
   fragS *target_frag;
 
-  if (xtensa_opcode_is_branch (isa, insn->opcode) == 0
-      && xtensa_opcode_is_jump (isa, insn->opcode) == 0)
-    return FALSE;
+  if (xtensa_opcode_is_branch (isa, insn->opcode) != 1
+      && xtensa_opcode_is_jump (isa, insn->opcode) != 1)
+    return false;
 
   for (i = 0; i < num_ops; i++)
     {
@@ -3728,30 +3900,30 @@ is_branch_jmp_to_next (TInsn *insn, fragS *fragP)
        }
     }
   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;
 }
 
 
@@ -3766,7 +3938,7 @@ xg_add_branch_and_loop_targets (TInsn *insn)
       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;
     }
 
@@ -3781,9 +3953,9 @@ xg_add_branch_and_loop_targets (TInsn *insn)
              && 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;
            }
        }
     }
@@ -3792,7 +3964,7 @@ xg_add_branch_and_loop_targets (TInsn *insn)
 
 /* 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;
@@ -3803,19 +3975,17 @@ xg_build_token_insn (BuildInstr *instr_spec, TInsn *old_insn, TInsn *new_insn)
     case INSTR_INSTR:
       new_insn->insn_type = ITYPE_INSN;
       new_insn->opcode = instr_spec->opcode;
-      new_insn->is_specific_opcode = FALSE;
-      new_insn->loc = old_insn->loc;
       break;
     case INSTR_LITERAL_DEF:
       new_insn->insn_type = ITYPE_LITERAL;
       new_insn->opcode = XTENSA_UNDEFINED;
-      new_insn->is_specific_opcode = FALSE;
-      new_insn->loc = old_insn->loc;
       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)
     {
@@ -3827,14 +3997,14 @@ xg_build_token_insn (BuildInstr *instr_spec, TInsn *old_insn, TInsn *new_insn)
        {
        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);
@@ -3843,44 +4013,44 @@ xg_build_token_insn (BuildInstr *instr_spec, TInsn *old_insn, TInsn *new_insn)
        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;
 }
 
 
@@ -3889,14 +4059,14 @@ xg_simplify_insn (TInsn *old_insn, TInsn *new_insn)
    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;
 
-  memset (&new_insn, 0, sizeof (TInsn));
+  tinsn_init (&new_insn);
 
   /* Narrow it if we can.  xg_simplify_insn now does all the
      appropriate checking (e.g., for the density option).  */
@@ -3907,14 +4077,18 @@ xg_expand_assembly_insn (IStack *istack, TInsn *orig_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);
@@ -3924,7 +4098,21 @@ xg_expand_assembly_insn (IStack *istack, TInsn *orig_insn)
   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
@@ -3935,7 +4123,7 @@ xg_expand_assembly_insn (IStack *istack, TInsn *orig_insn)
      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))
     {
@@ -3943,39 +4131,38 @@ xg_expand_assembly_insn (IStack *istack, TInsn *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;
 }
 
 
 /* Return TRUE if the section flags are marked linkonce
-   or the name is .gnu.linkonce*.  */
+   or the name is .gnu.linkonce.*.  */
 
-static bfd_boolean
+static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
+
+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.  */
-  if (!link_once_flags)
-    {
-      static size_t len = sizeof ".gnu.linkonce.t.";
+  if (!link_once_flags
+      && strncmp (segment_name (sec), ".gnu.linkonce.", linkonce_len) == 0)
+    link_once_flags = SEC_LINK_ONCE;
 
-      if (strncmp (segment_name (sec), ".gnu.linkonce.t.", len - 1) == 0)
-       link_once_flags = SEC_LINK_ONCE;
-    }
   return (link_once_flags != 0);
 }
 
@@ -3985,7 +4172,7 @@ xtensa_add_literal_sym (symbolS *sym)
 {
   sym_list *l;
 
-  l = (sym_list *) xmalloc (sizeof (sym_list));
+  l = XNEW (sym_list);
   l->sym = sym;
   l->next = literal_syms;
   literal_syms = l;
@@ -4006,16 +4193,15 @@ xtensa_create_literal_symbol (segT sec, fragS *frag)
      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);
 
-  frag->tc_frag_data.is_literal = TRUE;
   lit_num++;
   return symbolP;
 }
@@ -4028,6 +4214,9 @@ xg_assemble_literal (/* const */ TInsn *insn)
 {
   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
      larger constants.  Add a parameter later.  */
@@ -4038,8 +4227,8 @@ xg_assemble_literal (/* const */ TInsn *insn)
 
   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);
 
@@ -4063,25 +4252,36 @@ xg_assemble_literal (/* const */ TInsn *insn)
   frag_align (litalign, 0, 0);
   record_alignment (now_seg, litalign);
 
-  if (emit_val->X_op == O_pltrel)
+  switch (emit_val->X_op)
     {
-      char *p = frag_more (litsize);
+    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, 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, BFD_RELOC_XTENSA_PLT);
+                  litsize, emit_val, pcrel, reloc);
+      break;
+
+    default:
+      emit_expr (emit_val, litsize);
+      break;
     }
-  else
-    emit_expr (emit_val, litsize);
 
-  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;
-  frag_now->tc_frag_data.is_literal = TRUE;
 
   /* Go back.  */
   xtensa_restore_emit_state (&state);
@@ -4098,7 +4298,7 @@ xg_assemble_literal_space (/* const */ int size, int slot)
   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);
 
@@ -4106,13 +4306,12 @@ xg_assemble_literal_space (/* const */ int size, int slot)
   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->tc_frag_data.is_literal = TRUE;
   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);
@@ -4123,12 +4322,12 @@ xg_assemble_literal_space (/* const */ int size, int slot)
 /* 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)
 {
@@ -4148,33 +4347,33 @@ xg_add_opcode_fix (TInsn *tinsn,
     }
   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;
        }
     }
 
   if (opnum != get_relaxable_immed (opcode))
     {
       as_bad (_("invalid relocation for operand %i of '%s'"),
-             opnum, xtensa_opcode_name (xtensa_default_isa, opcode));
-      return FALSE;
+             opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
+      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, xtensa_opcode_name (xtensa_default_isa, opcode));
-      return FALSE;
+             opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
+      return false;
     }
 
   /* Next try the generic relocs.  */
@@ -4183,7 +4382,7 @@ xg_add_opcode_fix (TInsn *tinsn,
   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);
@@ -4191,38 +4390,32 @@ xg_add_opcode_fix (TInsn *tinsn,
     {
       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;
-
-  if (expr->X_add_symbol
-      && (S_IS_EXTERNAL (expr->X_add_symbol)
-         || S_IS_WEAK (expr->X_add_symbol)))
-    the_fix->fx_plt = TRUE;
-
-  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,
-                    xtensa_format fmt,
                     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);
 
@@ -4230,13 +4423,15 @@ xg_emit_insn_to_buf (TInsn *tinsn,
   if (has_symbolic_immed && build_fix)
     {
       /* Add a fixup.  */
+      xtensa_format fmt = xg_get_single_format (tinsn->opcode);
+      int slot = xg_get_single_slot (tinsn->opcode);
       int opnum = get_relaxable_immed (tinsn->opcode);
       expressionS *exp = &tinsn->tok[opnum];
 
-      if (!xg_add_opcode_fix (tinsn, opnum, fmt, 0, exp, fragP, offset))
-       ok = FALSE;
+      if (!xg_add_opcode_fix (tinsn, opnum, fmt, slot, exp, fragP, offset))
+       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;
@@ -4250,7 +4445,7 @@ xg_resolve_literals (TInsn *insn, symbolS *lit_sym)
   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;
@@ -4263,7 +4458,6 @@ xg_resolve_labels (TInsn *insn, symbolS *label_sym)
 {
   symbolS *sym = get_special_label_symbol ();
   int i;
-  /* assert (!insn->is_literal); */
   for (i = 0; i < insn->ntok; i++)
     if (insn->tok[i].X_add_symbol == sym)
       insn->tok[i].X_add_symbol = label_sym;
@@ -4274,7 +4468,7 @@ xg_resolve_labels (TInsn *insn, symbolS *label_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;
@@ -4296,21 +4490,21 @@ is_register_writer (const TInsn *insn, const char *regset, int regnum)
            {
              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
@@ -4327,9 +4521,9 @@ is_bad_loopend_opcode (const TInsn *tinsn)
       || opcode == xtensa_retw_n_opcode
       || opcode == xtensa_waiti_opcode
       || opcode == xtensa_rsr_lcount_opcode)
-    return TRUE;
+    return true;
 
-  return FALSE;
+  return false;
 }
 
 
@@ -4338,7 +4532,7 @@ is_bad_loopend_opcode (const TInsn *tinsn)
    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);
@@ -4347,7 +4541,7 @@ is_unaligned_label (symbolS *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)
@@ -4358,10 +4552,10 @@ is_unaligned_label (symbolS *sym)
       && (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;
 }
 
 
@@ -4382,22 +4576,22 @@ next_non_empty_frag (const fragS *fragP)
 }
 
 
-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;
 }
 
 
@@ -4447,8 +4641,34 @@ frag_format_size (const fragS *fragP)
 
   /* 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];
@@ -4465,6 +4685,26 @@ next_frag_format_size (const fragS *fragP)
 }
 
 
+/* In early Xtensa Processors, for reasons that are unclear, the ISA
+   required two-byte instructions to be treated as three-byte instructions
+   for loop instruction alignment.  This restriction was removed beginning
+   with Xtensa LX.  Now the only requirement on loop instruction alignment
+   is that the first instruction of the loop must appear at an address that
+   does not cross a fetch boundary.  */
+
+static int
+get_loop_align_size (int insn_size)
+{
+  if (insn_size == XTENSA_UNDEFINED)
+    return xtensa_fetch_width;
+
+  if (enforce_three_byte_loop_align && insn_size == 2)
+    return 3;
+
+  return insn_size;
+}
+
+
 /* If the next legit fragment is an end-of-loop marker,
    switch its state so it will instantiate a NOP.  */
 
@@ -4482,7 +4722,7 @@ update_next_frag_state (fragS *fragP)
                   || 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));
 
@@ -4493,7 +4733,7 @@ update_next_frag_state (fragS *fragP)
                   || 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));
     }
@@ -4512,7 +4752,7 @@ update_next_frag_state (fragS *fragP)
 }
 
 
-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,
@@ -4520,15 +4760,15 @@ next_frag_is_branch_target (const fragS *fragP)
   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.
@@ -4536,14 +4776,20 @@ next_frag_is_loop_target (const fragS *fragP)
   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)
 {
@@ -4566,7 +4812,7 @@ 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;
 }
@@ -4581,19 +4827,18 @@ xtensa_mark_literal_pool_location (void)
 {
   /* 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 && !directive_state[directive_absolute_literals])
+  if (use_literal_section)
     return;
 
-  frag_align (2, 0, 0);
-  record_alignment (now_seg, 2);
-
   /* We stash info in these frags so we can later move the literal's
      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);
@@ -4602,19 +4847,7 @@ xtensa_mark_literal_pool_location (void)
                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);
 }
 
 
@@ -4645,7 +4878,7 @@ build_nop (TInsn *tinsn, int size)
       else
        tinsn->opcode = xtensa_nop_opcode;
 
-      assert (tinsn->opcode != XTENSA_UNDEFINED);
+      gas_assert (tinsn->opcode != XTENSA_UNDEFINED);
     }
 }
 
@@ -4683,7 +4916,7 @@ get_expanded_loop_offset (xtensa_opcode opcode)
   /* 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)
@@ -4698,6 +4931,34 @@ get_expanded_loop_offset (xtensa_opcode 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;
 }
 
@@ -4716,25 +4977,75 @@ static void
 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);
+}
+
+
+static void
+xtensa_mark_frags_for_org (void)
+{
+  segT *seclist;
+
+  /* Walk over each fragment of all of the current segments.  If we find
+     a .org frag in any of the segments, mark all frags prior to it as
+     "no transform", which will prevent linker optimizations from messing
+     up the .org distance.  This should be done after
+     xtensa_find_unmarked_state_frags, because we don't want to worry here
+     about that function trashing the data we save here.  */
+
+  for (seclist = &stdoutput->sections;
+       seclist && *seclist;
+       seclist = &(*seclist)->next)
+    {
+      segT sec = *seclist;
+      segment_info_type *seginfo;
+      fragS *fragP;
+      flagword flags;
+      flags = bfd_section_flags (sec);
+      if (flags & SEC_DEBUGGING)
+       continue;
+      if (!(flags & SEC_ALLOC))
+       continue;
+
+      seginfo = seg_info (sec);
+      if (seginfo && seginfo->frchainP)
+       {
+         fragS *last_fragP = seginfo->frchainP->frch_root;
+         for (fragP = seginfo->frchainP->frch_root; fragP;
+              fragP = fragP->fr_next)
+           {
+             /* cvt_frag_to_fill has changed the fr_type of org frags to
+                rs_fill, so use the value as cached in rs_subtype here.  */
+             if (fragP->fr_subtype == RELAX_ORG)
+               {
+                 while (last_fragP != fragP->fr_next)
+                   {
+                     last_fragP->tc_frag_data.is_no_transform = true;
+                     last_fragP = last_fragP->fr_next;
+                   }
+               }
+           }
+       }
+    }
 }
 
 
@@ -4754,7 +5065,7 @@ xtensa_find_unmarked_state_frags (void)
       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))
@@ -4778,7 +5089,7 @@ xtensa_find_unmarked_state_frags (void)
                    }
                  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 =
@@ -4802,7 +5113,7 @@ xtensa_find_unaligned_branch_targets (bfd *abfd ATTRIBUTE_UNUSED,
                                      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;
 
@@ -4841,7 +5152,7 @@ xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED,
                             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;
@@ -4857,16 +5168,22 @@ xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED,
              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;
        }
@@ -4883,12 +5200,12 @@ xg_apply_fix_value (fixS *fixP, valueT val)
   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)
@@ -4948,6 +5265,26 @@ md_number_to_chars (char *buf, valueT val, int n)
     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
@@ -4959,23 +5296,18 @@ md_begin (void)
   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, .fini.literal and .init.literal sections.  */
+  /* Set up the literal sections.  */
   memset (&default_lit_sections, 0, sizeof (default_lit_sections));
-  default_lit_sections.init_lit_seg_name = INIT_LITERAL_SECTION_NAME;
-  default_lit_sections.fini_lit_seg_name = FINI_LITERAL_SECTION_NAME;
-  default_lit_sections.lit_seg_name = LITERAL_SECTION_NAME;
-  default_lit_sections.lit4_seg_name = LIT4_SECTION_NAME;
 
   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");
@@ -4988,9 +5320,11 @@ md_begin (void)
   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");
@@ -5006,11 +5340,25 @@ md_begin (void)
   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 ();
 }
 
 
@@ -5061,23 +5409,25 @@ xtensa_frob_label (symbolS *sym)
                frag_now->fr_symbol, frag_now->fr_offset, NULL);
 
       xtensa_set_frag_assembly_state (frag_now);
-      xtensa_move_labels (frag_now, 0, TRUE);
+      xtensa_move_labels (frag_now, 0);
     }
 
   /* 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, TRUE);
+      xtensa_move_labels (frag_now, 0);
     }
 
   /* We need to mark the following properties even if we aren't aligning.  */
@@ -5086,11 +5436,11 @@ xtensa_frob_label (symbolS *sym)
      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);
 }
@@ -5146,6 +5496,15 @@ xtensa_unrecognized_line (int ch)
 void
 xtensa_flush_pending_output (void)
 {
+  /* This line fixes a bug where automatically generated gstabs info
+     separates a function label from its entry instruction, ending up
+     with the literal position between the function label and the entry
+     instruction and crashing code.  It only happens with --gstabs and
+     --text-section-literals, and when several other obscure relaxation
+     conditions are met.  */
+  if (outputting_stabs_line_debug)
+    return;
+
   if (cur_vinsn.inside_bundle)
     as_bad (_("missing closing brace"));
 
@@ -5156,7 +5515,7 @@ xtensa_flush_pending_output (void)
       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 ();
 }
@@ -5187,7 +5546,7 @@ md_assemble (char *str)
   xtensa_isa isa = xtensa_default_isa;
   char *opname;
   unsigned opnamelen;
-  bfd_boolean has_underbar = FALSE;
+  bool has_underbar = false;
   char *arg_strings[MAX_INSN_ARGS];
   int num_args;
   TInsn orig_insn;             /* Original instruction from the input.  */
@@ -5196,9 +5555,7 @@ md_assemble (char *str)
 
   /* 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)
@@ -5213,15 +5570,86 @@ md_assemble (char *str)
   /* 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);
@@ -5274,28 +5702,21 @@ md_assemble (char *str)
       return;
     }
 
-  dwarf2_where (&orig_insn.loc);
+  /* 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);
 
-  /* Special-case for "entry" instruction.  */
-  if (orig_insn.opcode == xtensa_entry_opcode)
+  /* Check that immediate value for ENTRY is >= 16.  */
+  if (orig_insn.opcode == xtensa_entry_opcode && orig_insn.ntok >= 3)
     {
-      /* Check that the third opcode (#2) is >= 16.  */
-      if (orig_insn.ntok >= 3)
-       {
-         expressionS *exp = &orig_insn.tok[2];
-         switch (exp->X_op)
-           {
-           case O_constant:
-             if (exp->X_add_number < 16)
-               as_warn (_("entry instruction with stack decrement < 16"));
-             break;
-
-           default:
-             as_warn (_("entry instruction with non-constant decrement"));
-           }
-       }
+      expressionS *exp = &orig_insn.tok[2];
+      if (exp->X_op == O_constant && exp->X_add_number < 16)
+       as_warn (_("entry instruction with stack decrement < 16"));
     }
 
   /* Finish it off:
@@ -5318,6 +5739,8 @@ md_assemble (char *str)
 
   /* We've just emitted a new instruction so clear the list of labels.  */
   xtensa_clear_insn_labels ();
+
+  xtensa_check_frag_count ();
 }
 
 
@@ -5334,11 +5757,10 @@ xtensa_handle_align (fragS *fragP)
       && ! 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;
     }
 
@@ -5350,6 +5772,9 @@ xtensa_handle_align (fragS *fragP)
        as_bad_where (fragP->fr_file, fragP->fr_line,
                      _("unaligned entry instruction"));
     }
+
+  if (linkrelax && fragP->fr_type == rs_org)
+    fragP->fr_subtype = RELAX_ORG;
 }
 
 
@@ -5391,11 +5816,14 @@ md_pcrel_from (fixS *fixP)
   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);
@@ -5510,7 +5938,7 @@ xtensa_validate_fix_sub (fixS *fix)
    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] == '.')
@@ -5518,7 +5946,7 @@ xtensa_check_inside_bundle (void)
 
   /* This function must always return FALSE because it is called via a
      macro that has nothing to do with bundling.  */
-  return FALSE;
+  return false;
 }
 
 
@@ -5530,22 +5958,19 @@ xtensa_elf_section_change_hook (void)
   /* 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)
@@ -5555,43 +5980,66 @@ xtensa_fix_adjustable (fixS *fixP)
 }
 
 
+/* 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)
 {
   char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
-  valueT val;
+  valueT val = 0;
+
+  /* Subtracted symbols are only allowed for a few relocation types, and
+     unless linkrelax is enabled, they should not make it to this point.  */
+  if (fixP->fx_subsy && !(linkrelax && (fixP->fx_r_type == BFD_RELOC_32
+                                       || fixP->fx_r_type == BFD_RELOC_16
+                                       || fixP->fx_r_type == BFD_RELOC_8)))
+    as_bad_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 (linkrelax && fixP->fx_subsy)
+      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));
 
@@ -5607,12 +6055,28 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
          val = *valP;
          fixP->fx_done = 1;
        }
-      else
-       break;
+      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:
       md_number_to_chars (fixpos, val, fixP->fx_size);
       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:
@@ -5635,8 +6099,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
             by the linker, and it makes the object file disassembly
             readable when all branch targets are encoded in relocations.  */
 
-         assert (fixP->fx_addsy);
-         if (S_GET_SEGMENT (fixP->fx_addsy) == seg && !fixP->fx_plt
+         gas_assert (fixP->fx_addsy);
+         if (S_GET_SEGMENT (fixP->fx_addsy) == seg
              && !S_FORCE_RELOC (fixP->fx_addsy, 1))
            {
              val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
@@ -5652,8 +6116,10 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
        }
       break;
 
-    case BFD_RELOC_XTENSA_PLT:
     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:
@@ -5684,46 +6150,10 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 }
 
 
-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);
 }
 
 
@@ -5742,14 +6172,14 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 {
   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;
 
@@ -5765,7 +6195,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
     }
 
   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;
@@ -5788,7 +6218,7 @@ new_resource_table (void *data,
                    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;
@@ -5798,9 +6228,9 @@ new_resource_table (void *data,
   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;
 }
@@ -5830,17 +6260,15 @@ resize_resource_table (resource_table *rt, int cycles)
   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;
@@ -5853,9 +6281,9 @@ resources_available (resource_table *rt, xtensa_opcode opcode, int cycle)
       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;
 }
 
 
@@ -5888,7 +6316,7 @@ release_resources (resource_table *rt, xtensa_opcode opcode, int cycle)
     {
       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]--;
     }
 }
@@ -5919,7 +6347,7 @@ opcode_funcUnit_use_stage (void *data, xtensa_opcode opcode, int idx)
    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;
@@ -5927,13 +6355,13 @@ resources_conflict (vliw_insn *vinsn)
 
   /* 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,
@@ -5946,19 +6374,18 @@ resources_conflict (vliw_insn *vinsn)
   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 bundle_single_op (TInsn *);
 static void xg_assemble_vliw_tokens (vliw_insn *);
 
 
@@ -5969,8 +6396,7 @@ finish_vinsn (vliw_insn *vinsn)
 {
   IStack slotstack;
   int i;
-  char *file_name;
-  unsigned line;
+  int slots;
 
   if (find_vinsn_conflicts (vinsn))
     {
@@ -5982,11 +6408,18 @@ finish_vinsn (vliw_insn *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;"),
@@ -5997,21 +6430,18 @@ finish_vinsn (vliw_insn *vinsn)
       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;",
@@ -6028,12 +6458,12 @@ finish_vinsn (vliw_insn *vinsn)
        {
          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)
@@ -6046,7 +6476,7 @@ finish_vinsn (vliw_insn *vinsn)
 
          if (xg_expand_assembly_insn (&slotstack, &vinsn->slots[i]))
            {
-             e = TRUE;
+             e = true;
              continue;
            }
 
@@ -6063,12 +6493,12 @@ finish_vinsn (vliw_insn *vinsn)
              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)
@@ -6086,7 +6516,7 @@ finish_vinsn (vliw_insn *vinsn)
                }
              else
                {
-                 bundle_single_op (&slotstack.insn[slotstack.ninsn - 1]);
+                 emit_single_op (&slotstack.insn[slotstack.ninsn - 1]);
                  if (vinsn->format == XTENSA_UNDEFINED)
                    vinsn->slots[i].opcode = xtensa_nop_opcode;
                  else
@@ -6108,8 +6538,7 @@ finish_vinsn (vliw_insn *vinsn)
   /* 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;",
@@ -6127,6 +6556,8 @@ finish_vinsn (vliw_insn *vinsn)
   xg_assemble_vliw_tokens (vinsn);
 
   xg_clear_vinsn (vinsn);
+
+  xtensa_check_frag_count ();
 }
 
 
@@ -6162,22 +6593,22 @@ finish_vinsn (vliw_insn *vinsn)
 
 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++)
@@ -6199,22 +6630,22 @@ find_vinsn_conflicts (vliw_insn *vinsn)
                  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 queue"),
+                 as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same port"),
                          xtensa_opcode_name (isa, op1->opcode), i,
                          xtensa_opcode_name (isa, op2->opcode), j);
-                 return TRUE;
+                 return true;
                case 'f':
-                 as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) both have volatile queue accesses"),
+                 as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) both have volatile port accesses"),
                          xtensa_opcode_name (isa, op1->opcode), i,
                          xtensa_opcode_name (isa, op2->opcode), j);
-                 return TRUE;
+                 return true;
                default:
                  /* Everything is OK.  */
                  break;
@@ -6228,10 +6659,10 @@ find_vinsn_conflicts (vliw_insn *vinsn)
   if (branches > 1)
     {
       as_bad (_("multiple branches or jumps in the same bundle"));
-      return TRUE;
+      return true;
     }
 
-  return FALSE;
+  return false;
 }
 
 
@@ -6263,8 +6694,8 @@ check_t1_t2_reads_and_writes (TInsn *t1, TInsn *t2)
   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++)
@@ -6341,7 +6772,7 @@ check_t1_t2_reads_and_writes (TInsn *t1, TInsn *t2)
        {
          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'))
@@ -6370,9 +6801,9 @@ check_t1_t2_reads_and_writes (TInsn *t1, TInsn *t2)
        = xtensa_interfaceOperand_interface (isa, t2->opcode, j);
       int t2_class = xtensa_interface_class_id (isa, t2_int);
 
-      t2_inout = xtensa_interface_inout (isa, j);
+      t2_inout = xtensa_interface_inout (isa, t2_int);
       if (xtensa_interface_has_side_effect (isa, t2_int) == 1)
-       t2_volatile = TRUE;
+       t2_volatile = true;
 
       for (i = 0; i < t1_interfaces; i++)
        {
@@ -6380,9 +6811,9 @@ check_t1_t2_reads_and_writes (TInsn *t1, TInsn *t2)
            = xtensa_interfaceOperand_interface (isa, t1->opcode, j);
          int t1_class = xtensa_interface_class_id (isa, t1_int);
 
-         t1_inout = xtensa_interface_inout (isa, i);
+         t1_inout = xtensa_interface_inout (isa, t1_int);
          if (xtensa_interface_has_side_effect (isa, t1_int) == 1)
-           t1_volatile = TRUE;
+           t1_volatile = true;
 
          if (t1_volatile && t2_volatile && (t1_class == t2_class))
            return 'f';
@@ -6421,12 +6852,15 @@ xg_find_narrowest_format (vliw_insn *vinsn)
 
   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)
+    return xg_get_single_format (vinsn->slots[0].opcode);
+
   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;
@@ -6450,7 +6884,7 @@ xg_find_narrowest_format (vliw_insn *vinsn)
                  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))
                    {
@@ -6461,7 +6895,7 @@ xg_find_narrowest_format (vliw_insn *vinsn)
            }
          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;
@@ -6482,8 +6916,9 @@ xg_find_narrowest_format (vliw_insn *vinsn)
    each tinsn in the vinsn.  */
 
 static int
-relaxation_requirements (vliw_insn *vinsn)
+relaxation_requirements (vliw_insn *vinsn, bool *pfinish_frag)
 {
+  bool finish_frag = false;
   int extra_space = 0;
   int slot;
 
@@ -6494,20 +6929,13 @@ relaxation_requirements (vliw_insn *vinsn)
        {
          /* 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)
            {
              /* Difference in bytes between narrow and wide insns...  */
              extra_space += 1;
              tinsn->subtype = RELAX_NARROW;
-             tinsn->record_fix = TRUE;
-             break;
-           }
-         else
-           {
-             tinsn->record_fix = FALSE;
-             /* No extra_space needed.  */
            }
        }
       else
@@ -6532,59 +6960,48 @@ relaxation_requirements (vliw_insn *vinsn)
              tinsn->literal_space = max_literal_size;
 
              tinsn->subtype = RELAX_IMMED;
-             tinsn->record_fix = FALSE;
              extra_space += max_size;
            }
          else
            {
-             tinsn->record_fix = TRUE;
-             /* No extra space needed.  */
+             /* A fix record will be added for this instruction prior
+                to relaxation, so make it end the frag.  */
+             finish_frag = true;
            }
        }
     }
+  *pfinish_frag = finish_frag;
   return extra_space;
 }
 
 
 static void
-bundle_single_op (TInsn *orig_insn)
+bundle_tinsn (TInsn *tinsn, vliw_insn *vinsn)
 {
   xtensa_isa isa = xtensa_default_isa;
-  vliw_insn v;
-  int slot;
-
-  xg_init_vinsn (&v);
-  v.format = op_placement_table[orig_insn->opcode].narrowest;
-  assert (v.format != XTENSA_UNDEFINED);
-  v.num_slots = xtensa_format_num_slots (isa, v.format);
-
-  for (slot = 0;
-       !opcode_fits_format_slot (orig_insn->opcode, v.format, slot);
-       slot++)
-    {
-      v.slots[slot].opcode =
-       xtensa_format_slot_nop_opcode (isa, v.format, slot);
-      v.slots[slot].ntok = 0;
-      v.slots[slot].insn_type = ITYPE_INSN;
-    }
+  int slot, chosen_slot;
 
-  v.slots[slot] = *orig_insn;
-  slot++;
+  vinsn->format = xg_get_single_format (tinsn->opcode);
+  gas_assert (vinsn->format != XTENSA_UNDEFINED);
+  vinsn->num_slots = xtensa_format_num_slots (isa, vinsn->format);
 
-  for ( ; slot < v.num_slots; slot++)
+  chosen_slot = xg_get_single_slot (tinsn->opcode);
+  for (slot = 0; slot < vinsn->num_slots; slot++)
     {
-      v.slots[slot].opcode =
-       xtensa_format_slot_nop_opcode (isa, v.format, slot);
-      v.slots[slot].ntok = 0;
-      v.slots[slot].insn_type = ITYPE_INSN;
+      if (slot == chosen_slot)
+       vinsn->slots[slot] = *tinsn;
+      else
+       {
+         vinsn->slots[slot].opcode =
+           xtensa_format_slot_nop_opcode (isa, vinsn->format, slot);
+         vinsn->slots[slot].ntok = 0;
+         vinsn->slots[slot].insn_type = ITYPE_INSN;
+       }
     }
-
-  finish_vinsn (&v);
-  xg_free_vinsn (&v);
 }
 
 
-static bfd_boolean
+static bool
 emit_single_op (TInsn *orig_insn)
 {
   int i;
@@ -6602,11 +7019,16 @@ emit_single_op (TInsn *orig_insn)
        || 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++)
     {
@@ -6614,34 +7036,40 @@ emit_single_op (TInsn *orig_insn)
       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;
        case ITYPE_INSN:
-         if (lit_sym)
-           xg_resolve_literals (insn, lit_sym);
-         if (label_sym)
-           xg_resolve_labels (insn, label_sym);
-         bundle_single_op (insn);
+         {
+           vliw_insn v;
+           if (lit_sym)
+             xg_resolve_literals (insn, lit_sym);
+           if (label_sym)
+             xg_resolve_labels (insn, label_sym);
+           xg_init_vinsn (&v);
+           bundle_tinsn (insn, &v);
+           finish_vinsn (&v);
+           xg_free_vinsn (&v);
+         }
          break;
        default:
-         assert (0);
+         gas_assert (0);
          break;
        }
     }
-  return FALSE;
+  return false;
 }
 
 
@@ -6651,7 +7079,7 @@ total_frag_text_expansion (fragS *fragP)
   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;
@@ -6663,18 +7091,19 @@ total_frag_text_expansion (fragS *fragP)
 static void
 xg_assemble_vliw_tokens (vliw_insn *vinsn)
 {
-  bfd_boolean finish_frag = FALSE;
-  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;
-  struct dwarf2_line_info best_loc;
+  struct dwarf2_line_info debug_line;
+  bool loc_directive_seen = false;
+  TInsn *tinsn;
 
-  best_loc.line = INT_MAX;
+  memset (&debug_line, 0, sizeof (struct dwarf2_line_info));
 
   if (generating_literals)
     {
@@ -6691,7 +7120,7 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
   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]
@@ -6708,19 +7137,19 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
       && 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,
@@ -6729,15 +7158,22 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
       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_loc = vinsn->slots[i].loc.line < best_loc.line
-       ? vinsn->slots[i].loc : best_loc;
+      /* 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... */
@@ -6746,32 +7182,35 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
     {
       int max_fill;
 
+      /* Remember the symbol that marks the end of the loop in the frag
+        that marks the start of the loop.  This way we can easily find
+        the end of the loop at the beginning, without adding special code
+        to mark the loop instructions themselves.  */
+      symbolS *target_sym = NULL;
+      if (vinsn->slots[0].tok[1].X_op == O_symbol)
+       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,
-                 RELAX_ALIGN_NEXT_OPCODE,
-                 frag_now->fr_symbol,
-                 frag_now->fr_offset,
-                 NULL);
+                 RELAX_ALIGN_NEXT_OPCODE, target_sym, 0, NULL);
       else
        frag_var (rs_machine_dependent, 0, 0,
-                 RELAX_CHECK_ALIGN_NEXT_OPCODE, 0, 0, NULL);
+                 RELAX_CHECK_ALIGN_NEXT_OPCODE, target_sym, 0, NULL);
       xtensa_set_frag_assembly_state (frag_now);
-
-      xtensa_move_labels (frag_now, 0, FALSE);
     }
 
   if (vinsn->slots[0].opcode == xtensa_entry_opcode
       && !vinsn->slots[0].is_specific_opcode)
     {
       xtensa_mark_literal_pool_location ();
-      xtensa_move_labels (frag_now, 0, TRUE);
+      xtensa_move_labels (frag_now, 0);
       frag_var (rs_align_test, 1, 1, 0, NULL, 2, NULL);
     }
 
@@ -6785,53 +7224,58 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
                           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);
 
-  extra_space = relaxation_requirements (vinsn);
+  extra_space = relaxation_requirements (vinsn, &finish_frag);
 
   /* vinsn_to_insnbuf will produce the error.  */
   if (vinsn->format != XTENSA_UNDEFINED)
     {
       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, TRUE);
+  vinsn_to_insnbuf (vinsn, f, frag_now, false);
   if (vinsn->format == XTENSA_UNDEFINED)
     return;
 
   xtensa_insnbuf_to_chars (isa, vinsn->insnbuf, (unsigned char *) f, 0);
 
-  xtensa_dwarf2_emit_insn (insn_size + extra_space, &best_loc);
+  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_sub_symbols[slot] = tinsn->sub_symbol;
       frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset;
       frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag;
+      if (tinsn->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->record_fix
-         || tinsn->offset || tinsn->literal_frag || is_jump || is_branch)
-       finish_frag = TRUE;
+      if (tinsn->subtype || tinsn->symbol || tinsn->offset
+         || tinsn->literal_frag || is_jump || is_branch)
+       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)
     {
@@ -6847,17 +7291,17 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
      when converting them.  */
 
   /* "short_loop": Add a NOP if the loop is < 4 bytes.  */
-  if (xtensa_opcode_is_loop (isa, vinsn->slots[0].opcode)
+  if (xtensa_opcode_is_loop (isa, vinsn->slots[0].opcode) == 1
       && !vinsn->slots[0].is_specific_opcode)
     {
       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);
@@ -6867,8 +7311,8 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
         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);
@@ -6879,18 +7323,21 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
     {
       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);
@@ -6907,7 +7354,7 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
       && 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);
@@ -6928,11 +7375,13 @@ static void xtensa_cleanup_align_frags (void);
 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);
 static void xtensa_fix_short_loop_frags (void);
 static void xtensa_sanity_check (void);
+static void xtensa_add_config_info (void);
 
 void
 xtensa_end (void)
@@ -6940,7 +7389,7 @@ xtensa_end (void)
   directive_balance ();
   xtensa_flush_pending_output ();
 
-  past_xtensa_end = TRUE;
+  past_xtensa_end = true;
 
   xtensa_move_literals ();
 
@@ -6958,132 +7407,714 @@ xtensa_end (void)
 
   if (workaround_short_loop && maybe_has_short_loop)
     xtensa_fix_short_loop_frags ();
-  xtensa_mark_narrow_branches ();
+  if (align_targets)
+    xtensa_mark_narrow_branches ();
   xtensa_mark_zcl_first_insns ();
 
   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;
+};
 
-static void
-xtensa_cleanup_align_frags (void)
+struct trampoline_chain_index
 {
-  frchainS *frchP;
+  struct trampoline_chain *entry;
+  size_t n_entries;
+  size_t n_max;
+  bool needs_sorting;
+};
 
-  for (frchP = frchain_root; frchP; frchP = frchP->frch_next)
-    {
-      fragS *fragP;
-      /* Walk over all of the fragments in a subsection.  */
-      for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
-       {
-         if ((fragP->fr_type == rs_align
-              || fragP->fr_type == rs_align_code
-              || (fragP->fr_type == rs_machine_dependent
-                  && (fragP->fr_subtype == RELAX_DESIRE_ALIGN
-                      || fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)))
-             && fragP->fr_fix == 0)
-           {
-             fragS *next = fragP->fr_next;
+struct trampoline_index
+{
+  fragS **entry;
+  size_t n_entries;
+  size_t n_max;
+};
 
-             while (next
-                    && next->fr_fix == 0
-                    && next->fr_type == rs_machine_dependent
-                    && next->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)
-               {
-                 frag_wane (next);
-                 next = next->fr_next;
-               }
-           }
-         /* If we don't widen branch targets, then they
-            will be easier to align.  */
-         if (fragP->tc_frag_data.is_branch_target
-             && fragP->fr_opcode == fragP->fr_literal
-             && fragP->fr_type == rs_machine_dependent
-             && fragP->fr_subtype == RELAX_SLOTS
-             && fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
-           frag_wane (fragP);
-         if (fragP->fr_type == rs_machine_dependent
-             && fragP->fr_subtype == RELAX_UNREACHABLE)
-           fragP->tc_frag_data.is_unreachable = TRUE;
-       }
-    }
-}
+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;
 
-/* Re-process all of the fragments looking to convert all of the
-   RELAX_DESIRE_ALIGN_IF_TARGET fragments.  If there is a branch
-   target in the next fragment, convert this to RELAX_DESIRE_ALIGN.
-   Otherwise, convert to a .fill 0.  */
 
 static void
-xtensa_fix_target_frags (void)
+xtensa_maybe_create_trampoline_frag (void)
 {
-  frchainS *frchP;
+  if (!use_trampolines)
+    return;
 
-  /* When this routine is called, all of the subsections are still intact
-     so we walk over subsections instead of sections.  */
-  for (frchP = frchain_root; frchP; frchP = frchP->frch_next)
+  /* 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)
     {
-      fragS *fragP;
+      xtensa_create_trampoline_frag (false);
+      clear_frag_count ();
+      unreachable_count = 0;
+    }
+}
 
-      /* Walk over all of the fragments in a subsection.  */
-      for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
-       {
-         if (fragP->fr_type == rs_machine_dependent
-             && fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)
-           {
-             if (next_frag_is_branch_target (fragP))
-               fragP->fr_subtype = RELAX_DESIRE_ALIGN;
-             else
-               frag_wane (fragP);
-           }
-       }
+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 bfd_boolean is_narrow_branch_guaranteed_in_range (fragS *, TInsn *);
+static xtensa_insnbuf litpool_buf = NULL;
+static xtensa_insnbuf litpool_slotbuf = NULL;
 
-static void
-xtensa_mark_narrow_branches (void)
+#define TRAMPOLINE_FRAG_SIZE 3000
+
+static struct trampoline_seg *
+find_trampoline_seg (asection *seg)
 {
-  frchainS *frchP;
+  struct trampoline_seg *ts = trampoline_seg_list.next;
+  static struct trampoline_seg *mr;
 
-  for (frchP = frchain_root; frchP; frchP = frchP->frch_next)
+  if (mr && mr->seg == seg)
+    return mr;
+
+  for ( ; ts; ts = ts->next)
     {
-      fragS *fragP;
-      /* Walk over all of the fragments in a subsection.  */
-      for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+      if (ts->seg == seg)
        {
-         if (fragP->fr_type == rs_machine_dependent
-             && fragP->fr_subtype == RELAX_SLOTS
-             && fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED)
+         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)
            {
-             vliw_insn vinsn;
-             const expressionS *expr;
-             symbolS *symbolP;
-
-             vinsn_from_chars (&vinsn, fragP->fr_opcode);
-             tinsn_immed_from_frag (&vinsn.slots[0], fragP, 0);
-
-             expr = &vinsn.slots[0].tok[1];
-             symbolP = expr->X_add_symbol;
-
-             if (vinsn.num_slots == 1
-                 && xtensa_opcode_is_branch (xtensa_default_isa,
-                                             vinsn.slots[0].opcode)
-                 && xg_get_single_size (vinsn.slots[0].opcode) == 2
-                 && is_narrow_branch_guaranteed_in_range (fragP,
-                                                          &vinsn.slots[0]))
-               {
-                 fragP->fr_subtype = RELAX_SLOTS;
-                 fragP->tc_frag_data.slot_subtypes[0] = RELAX_NARROW;
-               }
+             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)
+{
+  frchainS *frchP;
+  asection *s;
+
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
+       /* Walk over all of the fragments in a subsection.  */
+       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+         {
+           if ((fragP->fr_type == rs_align
+                || fragP->fr_type == rs_align_code
+                || (fragP->fr_type == rs_machine_dependent
+                    && (fragP->fr_subtype == RELAX_DESIRE_ALIGN
+                        || fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)))
+               && fragP->fr_fix == 0)
+             {
+               fragS *next = fragP->fr_next;
+
+               while (next
+                      && next->fr_fix == 0
+                      && next->fr_type == rs_machine_dependent
+                      && next->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)
+                 {
+                   frag_wane (next);
+                   next = next->fr_next;
+                 }
+             }
+           /* If we don't widen branch targets, then they
+              will be easier to align.  */
+           if (fragP->tc_frag_data.is_branch_target
+               && fragP->fr_opcode == fragP->fr_literal
+               && fragP->fr_type == rs_machine_dependent
+               && fragP->fr_subtype == RELAX_SLOTS
+               && fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
+             frag_wane (fragP);
+           if (fragP->fr_type == rs_machine_dependent
+               && fragP->fr_subtype == RELAX_UNREACHABLE)
+             fragP->tc_frag_data.is_unreachable = true;
+         }
+      }
+}
+
+
+/* Re-process all of the fragments looking to convert all of the
+   RELAX_DESIRE_ALIGN_IF_TARGET fragments.  If there is a branch
+   target in the next fragment, convert this to RELAX_DESIRE_ALIGN.
+   Otherwise, convert to a .fill 0.  */
+
+static void
+xtensa_fix_target_frags (void)
+{
+  frchainS *frchP;
+  asection *s;
+
+  /* When this routine is called, all of the subsections are still intact
+     so we walk over subsections instead of sections.  */
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
+
+       /* Walk over all of the fragments in a subsection.  */
+       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+         {
+           if (fragP->fr_type == rs_machine_dependent
+               && fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)
+             {
+               if (next_frag_is_branch_target (fragP))
+                 fragP->fr_subtype = RELAX_DESIRE_ALIGN;
+               else
+                 frag_wane (fragP);
+             }
+         }
+      }
+}
+
+
+static bool is_narrow_branch_guaranteed_in_range (fragS *, TInsn *);
+
+static void
+xtensa_mark_narrow_branches (void)
+{
+  frchainS *frchP;
+  asection *s;
+
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
+       /* Walk over all of the fragments in a subsection.  */
+       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+         {
+           if (fragP->fr_type == rs_machine_dependent
+               && fragP->fr_subtype == RELAX_SLOTS
+               && fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED)
+             {
+               vliw_insn vinsn;
+
+               vinsn_from_chars (&vinsn, fragP->fr_opcode);
+               tinsn_immed_from_frag (&vinsn.slots[0], fragP, 0);
+
+               if (vinsn.num_slots == 1
+                   && xtensa_opcode_is_branch (xtensa_default_isa,
+                                               vinsn.slots[0].opcode) == 1
+                   && xg_get_single_size (vinsn.slots[0].opcode) == 2
+                   && is_narrow_branch_guaranteed_in_range (fragP,
+                                                            &vinsn.slots[0]))
+                 {
+                   fragP->fr_subtype = RELAX_SLOTS;
+                   fragP->tc_frag_data.slot_subtypes[0] = RELAX_NARROW;
+                   fragP->tc_frag_data.is_aligning_branch = 1;
+                 }
+             }
+         }
+      }
+}
+
 
 /* A branch is typically widened only when its target is out of
    range.  However, we would like to widen them to align a subsequent
@@ -7103,16 +8134,22 @@ 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;
-  fragS *target_frag = symbol_get_frag (symbolP);
-  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 (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.  */
@@ -7123,8 +8160,8 @@ is_narrow_branch_guaranteed_in_range (fragS *fragP, TInsn *tinsn)
       fragP = fragP->fr_next;
     }
   if (max_distance <= MAX_IMMED6 && fragP == target_frag)
-    return TRUE;
-  return FALSE;
+    return true;
+  return false;
 }
 
 
@@ -7132,28 +8169,132 @@ static void
 xtensa_mark_zcl_first_insns (void)
 {
   frchainS *frchP;
+  asection *s;
+
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
+       /* Walk over all of the fragments in a subsection.  */
+       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+         {
+           if (fragP->fr_type == rs_machine_dependent
+               && (fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE
+                   || fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE))
+             {
+               /* Find the loop frag.  */
+               fragS *loop_frag = next_non_empty_frag (fragP);
+               /* Find the first insn 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;
+                   /* 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
+                       && targ_frag->fr_subtype == RELAX_SLOTS
+                       && (targ_frag->tc_frag_data.slot_subtypes[0]
+                           == RELAX_NARROW))
+                     {
+                       if (targ_frag->tc_frag_data.is_aligning_branch)
+                         targ_frag->tc_frag_data.slot_subtypes[0] = RELAX_IMMED;
+                       else
+                         {
+                           frag_wane (targ_frag);
+                           targ_frag->tc_frag_data.slot_subtypes[0] = 0;
+                         }
+                     }
+                 }
+               if (fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE)
+                 frag_wane (fragP);
+             }
+         }
+      }
+}
+
+
+/* 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 (frchP = frchain_root; frchP; frchP = frchP->frch_next)
+  for (expr_sym = expr_symbols; expr_sym;
+       expr_sym = symbol_get_tc (expr_sym)->next_expr_symbol)
     {
-      fragS *fragP;
-      /* Walk over all of the fragments in a subsection.  */
-      for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+      expressionS *exp = symbol_get_value_expression (expr_sym);
+
+      if (exp->X_op == O_subtract)
        {
-         if (fragP->fr_type == rs_machine_dependent
-             && (fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE
-                 || fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE))
+         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))
            {
-             /* Find the loop frag.  */
-             fragS *targ_frag = next_non_empty_frag (fragP);
-             /* Find the first insn frag.  */
-             targ_frag = next_non_empty_frag (targ_frag);
-
-             /* Of course, sometimes (mostly for toy test cases) a
-                zero-cost loop instruction is the last in a section.  */
-             if (targ_frag)
-               targ_frag->tc_frag_data.is_first_loop_insn = TRUE;
-             if (fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE)
-               frag_wane (fragP);
+             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;
            }
        }
     }
@@ -7165,40 +8306,42 @@ xtensa_mark_zcl_first_insns (void)
    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)
 {
   frchainS *frchP;
+  asection *s;
 
   /* When this routine is called, all of the subsections are still intact
      so we walk over subsections instead of sections.  */
-  for (frchP = frchain_root; frchP; frchP = frchP->frch_next)
-    {
-      fragS *fragP;
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
 
-      /* Walk over all of the fragments in a subsection.  */
-      for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
-       {
-         if (fragP->fr_type == rs_machine_dependent
-             && fragP->fr_subtype == RELAX_ADD_NOP_IF_A0_B_RETW)
-           {
-             if (next_instrs_are_b_retw (fragP))
-               {
-                 if (fragP->tc_frag_data.is_no_transform)
-                   as_bad (_("instruction sequence (write a0, branch, retw) may trigger hardware errata"));
-                 else
-                   relax_frag_add_nop (fragP);
-               }
-             frag_wane (fragP);
-           }
-       }
-    }
+       /* Walk over all of the fragments in a subsection.  */
+       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+         {
+           if (fragP->fr_type == rs_machine_dependent
+               && fragP->fr_subtype == RELAX_ADD_NOP_IF_A0_B_RETW)
+             {
+               if (next_instrs_are_b_retw (fragP))
+                 {
+                   if (fragP->tc_frag_data.is_no_transform)
+                     as_bad (_("instruction sequence (write a0, branch, retw) may trigger hardware errata"));
+                   else
+                     relax_frag_add_nop (fragP);
+                 }
+               frag_wane (fragP);
+             }
+         }
+      }
 }
 
 
-static bfd_boolean
+static bool
 next_instrs_are_b_retw (fragS *fragP)
 {
   xtensa_opcode opcode;
@@ -7207,9 +8350,9 @@ next_instrs_are_b_retw (fragS *fragP)
   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)
     {
@@ -7218,14 +8361,14 @@ next_instrs_are_b_retw (fragS *fragP)
     }
 
   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++)
     {
@@ -7237,7 +8380,7 @@ next_instrs_are_b_retw (fragS *fragP)
     }
 
   if (!branch_seen)
-    return FALSE;
+    return false;
 
   offset += xtensa_format_length (isa, fmt);
   if (offset == next_fragP->fr_fix)
@@ -7247,7 +8390,7 @@ next_instrs_are_b_retw (fragS *fragP)
     }
 
   if (next_fragP == NULL)
-    return FALSE;
+    return false;
 
   /* Check for the retw/retw.n.  */
   xtensa_insnbuf_from_chars
@@ -7258,15 +8401,15 @@ next_instrs_are_b_retw (fragS *fragP)
      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;
 }
 
 
@@ -7275,60 +8418,62 @@ next_instrs_are_b_retw (fragS *fragP)
    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)
 {
   frchainS *frchP;
+  asection *s;
 
   /* When this routine is called, all of the subsections are still intact
      so we walk over subsections instead of sections.  */
-  for (frchP = frchain_root; frchP; frchP = frchP->frch_next)
-    {
-      fragS *fragP;
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
 
-      /* Walk over all of the fragments in a subsection.  */
-      for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
-       {
-         if (fragP->fr_type == rs_machine_dependent
-             && fragP->fr_subtype == RELAX_ADD_NOP_IF_PRE_LOOP_END)
-           {
-             if (next_instr_is_loop_end (fragP))
-               {
-                 if (fragP->tc_frag_data.is_no_transform)
-                   as_bad (_("branching or jumping to a loop end may trigger hardware errata"));
-                 else
-                   relax_frag_add_nop (fragP);
-               }
-             frag_wane (fragP);
-           }
-       }
-    }
+       /* Walk over all of the fragments in a subsection.  */
+       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+         {
+           if (fragP->fr_type == rs_machine_dependent
+               && fragP->fr_subtype == RELAX_ADD_NOP_IF_PRE_LOOP_END)
+             {
+               if (next_instr_is_loop_end (fragP))
+                 {
+                   if (fragP->tc_frag_data.is_no_transform)
+                     as_bad (_("branching or jumping to a loop end may trigger hardware errata"));
+                   else
+                     relax_frag_add_nop (fragP);
+                 }
+               frag_wane (fragP);
+             }
+         }
+      }
 }
 
 
-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;
 }
 
 
@@ -7339,91 +8484,74 @@ next_instr_is_loop_end (fragS *fragP)
    .fill 0.  */
 
 static offsetT min_bytes_to_other_loop_end
-  (fragS *, fragS *, offsetT, offsetT);
+  (fragS *, fragS *, offsetT);
 
 static void
 xtensa_fix_close_loop_end_frags (void)
 {
   frchainS *frchP;
+  asection *s;
 
   /* When this routine is called, all of the subsections are still intact
      so we walk over subsections instead of sections.  */
-  for (frchP = frchain_root; frchP; frchP = frchP->frch_next)
-    {
-      fragS *fragP;
-
-      fragS *current_target = NULL;
-      offsetT current_offset = 0;
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
 
-      /* Walk over all of the fragments in a subsection.  */
-      for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
-       {
-         if (fragP->fr_type == rs_machine_dependent
-             && ((fragP->fr_subtype == RELAX_IMMED)
-                 || ((fragP->fr_subtype == RELAX_SLOTS)
-                     && (fragP->tc_frag_data.slot_subtypes[0]
-                         == RELAX_IMMED))))
-           {
-             /* Read it.  If the instruction is a loop, get the target.  */
-             TInsn t_insn;
-             tinsn_from_chars (&t_insn, fragP->fr_opcode, 0);
-             if (xtensa_opcode_is_loop (xtensa_default_isa,
-                                        t_insn.opcode) == 1)
-               {
-                 /* Get the current fragment target.  */
-                 if (fragP->tc_frag_data.slot_symbols[0])
-                   {
-                     symbolS *sym = fragP->tc_frag_data.slot_symbols[0];
-                     current_target = symbol_get_frag (sym);
-                     current_offset = fragP->fr_offset;
-                   }
-               }
-           }
+       fragS *current_target = NULL;
 
-         if (current_target
-             && fragP->fr_type == rs_machine_dependent
-             && fragP->fr_subtype == RELAX_ADD_NOP_IF_CLOSE_LOOP_END)
-           {
-             offsetT min_bytes;
-             int bytes_added = 0;
+       /* Walk over all of the fragments in a subsection.  */
+       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+         {
+           if (fragP->fr_type == rs_machine_dependent
+               && ((fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE)
+                   || (fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE)))
+             current_target = symbol_get_frag (fragP->fr_symbol);
+
+           if (current_target
+               && fragP->fr_type == rs_machine_dependent
+               && fragP->fr_subtype == RELAX_ADD_NOP_IF_CLOSE_LOOP_END)
+             {
+               offsetT min_bytes;
+               int bytes_added = 0;
 
 #define REQUIRED_LOOP_DIVIDING_BYTES 12
-             /* Max out at 12.  */
-             min_bytes = min_bytes_to_other_loop_end
-               (fragP->fr_next, current_target, current_offset,
-                REQUIRED_LOOP_DIVIDING_BYTES);
-
-             if (min_bytes < REQUIRED_LOOP_DIVIDING_BYTES)
-               {
-                 if (fragP->tc_frag_data.is_no_transform)
-                   as_bad (_("loop end too close to another loop end may trigger hardware errata"));
-                 else
-                   {
-                     while (min_bytes + bytes_added
-                            < REQUIRED_LOOP_DIVIDING_BYTES)
-                       {
-                         int length = 3;
-
-                         if (fragP->fr_var < length)
-                           as_fatal (_("fr_var %lu < length %d"),
-                                     (long) fragP->fr_var, length);
-                         else
-                           {
-                             assemble_nop (length,
-                                           fragP->fr_literal + fragP->fr_fix);
-                             fragP->fr_fix += length;
-                             fragP->fr_var -= length;
-                           }
-                         bytes_added += length;
-                       }
-                   }
-               }
-             frag_wane (fragP);
-           }
-         assert (fragP->fr_type != rs_machine_dependent
-                 || fragP->fr_subtype != RELAX_ADD_NOP_IF_CLOSE_LOOP_END);
-       }
-    }
+               /* Max out at 12.  */
+               min_bytes = min_bytes_to_other_loop_end
+                 (fragP->fr_next, current_target, REQUIRED_LOOP_DIVIDING_BYTES);
+
+               if (min_bytes < REQUIRED_LOOP_DIVIDING_BYTES)
+                 {
+                   if (fragP->tc_frag_data.is_no_transform)
+                     as_bad (_("loop end too close to another loop end may trigger hardware errata"));
+                   else
+                     {
+                       while (min_bytes + bytes_added
+                              < REQUIRED_LOOP_DIVIDING_BYTES)
+                         {
+                           int length = 3;
+
+                           if (fragP->fr_var < length)
+                             as_fatal (_("fr_var %lu < length %d"),
+                                       (long) fragP->fr_var, length);
+                           else
+                             {
+                               assemble_nop (length,
+                                             fragP->fr_literal + fragP->fr_fix);
+                               fragP->fr_fix += length;
+                               fragP->fr_var -= length;
+                             }
+                           bytes_added += length;
+                         }
+                     }
+                 }
+               frag_wane (fragP);
+             }
+           gas_assert (fragP->fr_type != rs_machine_dependent
+                   || fragP->fr_subtype != RELAX_ADD_NOP_IF_CLOSE_LOOP_END);
+         }
+      }
 }
 
 
@@ -7432,7 +8560,6 @@ static offsetT unrelaxed_frag_min_size (fragS *);
 static offsetT
 min_bytes_to_other_loop_end (fragS *fragP,
                             fragS *current_target,
-                            offsetT current_offset,
                             offsetT max_size)
 {
   offsetT offset = 0;
@@ -7444,11 +8571,11 @@ min_bytes_to_other_loop_end (fragS *fragP,
     {
       if (current_fragP->tc_frag_data.is_loop_target
          && current_fragP != current_target)
-       return offset + current_offset;
+       return offset;
 
       offset += unrelaxed_frag_min_size (current_fragP);
 
-      if (offset + current_offset >= max_size)
+      if (offset >= max_size)
        return max_size;
     }
   return max_size;
@@ -7497,7 +8624,7 @@ unrelaxed_frag_max_size (fragS *fragP)
       break;
     default:
       /* We had darn well better know how big it is.  */
-      assert (0);
+      gas_assert (0);
       break;
     }
 
@@ -7521,69 +8648,56 @@ unrelaxed_frag_max_size (fragS *fragP)
    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)
 {
   frchainS *frchP;
+  asection *s;
 
   /* When this routine is called, all of the subsections are still intact
      so we walk over subsections instead of sections.  */
-  for (frchP = frchain_root; frchP; frchP = frchP->frch_next)
-    {
-      fragS *fragP;
-      fragS *current_target = NULL;
-      offsetT current_offset = 0;
-      xtensa_opcode current_opcode = XTENSA_UNDEFINED;
-
-      /* Walk over all of the fragments in a subsection.  */
-      for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
-       {
-         /* Check on the current loop.  */
-         if (fragP->fr_type == rs_machine_dependent
-             && ((fragP->fr_subtype == RELAX_IMMED)
-                 || ((fragP->fr_subtype == RELAX_SLOTS)
-                     && (fragP->tc_frag_data.slot_subtypes[0]
-                         == RELAX_IMMED))))
-           {
-             TInsn t_insn;
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
+       xtensa_opcode current_opcode = XTENSA_UNDEFINED;
 
-             /* Read it.  If the instruction is a loop, get the target.  */
-             tinsn_from_chars (&t_insn, fragP->fr_opcode, 0);
-             if (xtensa_opcode_is_loop (xtensa_default_isa,
-                                        t_insn.opcode) == 1)
-               {
-                 /* Get the current fragment target.  */
-                 if (fragP->tc_frag_data.slot_symbols[0])
-                   {
-                     symbolS *sym = fragP->tc_frag_data.slot_symbols[0];
-                     current_target = symbol_get_frag (sym);
-                     current_offset = fragP->fr_offset;
-                     current_opcode = t_insn.opcode;
-                   }
-               }
-           }
+       /* Walk over all of the fragments in a subsection.  */
+       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+         {
+           if (fragP->fr_type == rs_machine_dependent
+               && ((fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE)
+                   || (fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE)))
+             {
+               TInsn t_insn;
+               fragS *loop_frag = next_non_empty_frag (fragP);
+               tinsn_from_chars (&t_insn, loop_frag->fr_opcode, 0);
+               current_opcode = t_insn.opcode;
+               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
-                 && (branch_before_loop_end (fragP->fr_next)
-                     || (workaround_all_short_loops
-                         && current_opcode != XTENSA_UNDEFINED
-                         && current_opcode != xtensa_loop_opcode)))
-               {
-                 if (fragP->tc_frag_data.is_no_transform)
-                   as_bad (_("loop containing less than three instructions may trigger hardware errata"));
-                 else
-                   relax_frag_add_nop (fragP);
-               }
-             frag_wane (fragP);
-           }
-       }
-    }
+           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
+                   && (branch_before_loop_end (fragP->fr_next)
+                       || (workaround_all_short_loops
+                           && current_opcode != XTENSA_UNDEFINED
+                           && current_opcode != xtensa_loop_opcode)))
+                 {
+                   if (fragP->tc_frag_data.is_no_transform)
+                     as_bad (_("loop containing less than three instructions may trigger hardware errata"));
+                   else
+                     relax_frag_add_nop (fragP);
+                 }
+               frag_wane (fragP);
+             }
+         }
+      }
 }
 
 
@@ -7591,7 +8705,7 @@ static int unrelaxed_frag_min_insn_count (fragS *);
 
 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;
@@ -7629,7 +8743,7 @@ unrelaxed_frag_min_insn_count (fragS *fragP)
   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;
@@ -7659,9 +8773,9 @@ unrelaxed_frag_min_insn_count (fragS *fragP)
 }
 
 
-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;
@@ -7671,21 +8785,21 @@ branch_before_loop_end (fragS *base_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);
@@ -7700,7 +8814,7 @@ unrelaxed_frag_has_b_j (fragS *fragP)
        (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++)
        {
@@ -7708,68 +8822,69 @@ unrelaxed_frag_has_b_j (fragS *fragP)
            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);
-  for (frchP = frchain_root; frchP; frchP = frchP->frch_next)
-    {
-      fragS *fragP;
-
-      /* Walk over all of the fragments in a subsection.  */
-      for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
-       {
-         /* Currently we only check for empty loops here.  */
-         if (fragP->fr_type == rs_machine_dependent
-             && fragP->fr_subtype == RELAX_IMMED)
-           {
-             static xtensa_insnbuf insnbuf = NULL;
-             TInsn t_insn;
-
-             if (fragP->fr_opcode != NULL)
-               {
-                 if (!insnbuf)
-                   insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
-                 tinsn_from_chars (&t_insn, fragP->fr_opcode, 0);
-                 tinsn_immed_from_frag (&t_insn, fragP, 0);
+  file_name = as_where (&line);
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
 
-                 if (xtensa_opcode_is_loop (xtensa_default_isa,
-                                            t_insn.opcode) == 1)
-                   {
-                     if (is_empty_loop (&t_insn, fragP))
-                       {
-                         new_logical_line (fragP->fr_file, fragP->fr_line);
-                         as_bad (_("invalid empty loop"));
-                       }
-                     if (!is_local_forward_loop (&t_insn, fragP))
-                       {
-                         new_logical_line (fragP->fr_file, fragP->fr_line);
-                         as_bad (_("loop target does not follow "
-                                   "loop instruction in section"));
-                       }
-                   }
-               }
-           }
-       }
-    }
+       /* Walk over all of the fragments in a subsection.  */
+       for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+         {
+           if (fragP->fr_type == rs_machine_dependent
+               && fragP->fr_subtype == RELAX_SLOTS
+               && fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED)
+             {
+               static xtensa_insnbuf insnbuf = NULL;
+               TInsn t_insn;
+
+               if (fragP->fr_opcode != NULL)
+                 {
+                   if (!insnbuf)
+                     insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
+                   tinsn_from_chars (&t_insn, fragP->fr_opcode, 0);
+                   tinsn_immed_from_frag (&t_insn, fragP, 0);
+
+                   if (xtensa_opcode_is_loop (xtensa_default_isa,
+                                              t_insn.opcode) == 1)
+                     {
+                       if (is_empty_loop (&t_insn, fragP))
+                         {
+                           new_logical_line (fragP->fr_file, fragP->fr_line);
+                           as_bad (_("invalid empty loop"));
+                         }
+                       if (!is_local_forward_loop (&t_insn, fragP))
+                         {
+                           new_logical_line (fragP->fr_file, fragP->fr_line);
+                           as_bad (_("loop target does not follow "
+                                     "loop instruction in section"));
+                         }
+                     }
+                 }
+             }
+         }
+      }
   new_logical_line (file_name, line);
 }
 
@@ -7778,36 +8893,36 @@ xtensa_sanity_check (void)
 
 /* Return TRUE if the loop target is the next non-zero fragment.  */
 
-static bfd_boolean
+static bool
 is_empty_loop (const TInsn *insn, fragS *fragP)
 {
-  const expressionS *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.  */
@@ -7817,41 +8932,41 @@ is_empty_loop (const TInsn *insn, fragS *fragP)
        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) == 0)
-    return FALSE;
+  if (xtensa_opcode_is_loop (xtensa_default_isa, insn->opcode) != 1)
+    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.  */
@@ -7861,10 +8976,58 @@ is_local_forward_loop (const TInsn *insn, fragS *fragP)
        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
+
+static void
+xtensa_add_config_info (void)
+{
+  asection *info_sec;
+  char *data, *p;
+  int sz;
+
+  info_sec = subseg_new (".xtensa.info", 0);
+  bfd_set_section_flags (info_sec, SEC_HAS_CONTENTS | SEC_READONLY);
+
+  data = XNEWVEC (char, 100);
+  sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n",
+          XSHAL_USE_ABSOLUTE_LITERALS, xtensa_abi_choice ());
+  sz = strlen (data) + 1;
+
+  /* Add enough null terminators to pad to a word boundary.  */
+  do
+    data[sz++] = 0;
+  while ((sz & 3) != 0);
+
+  /* Follow the standard note section layout:
+     First write the length of the name string.  */
+  p = frag_more (4);
+  md_number_to_chars (p, (valueT) XTINFO_NAMESZ, 4);
+
+  /* Next comes the length of the "descriptor", i.e., the actual data.  */
+  p = frag_more (4);
+  md_number_to_chars (p, (valueT) sz, 4);
+
+  /* Write the note type.  */
+  p = frag_more (4);
+  md_number_to_chars (p, (valueT) XTINFO_TYPE, 4);
+
+  /* Write the name field.  */
+  p = frag_more (XTINFO_NAMESZ);
+  memcpy (p, XTINFO_NAME, XTINFO_NAMESZ);
+
+  /* Finally, write the descriptor.  */
+  p = frag_more (sz);
+  memcpy (p, data, sz);
+
+  free (data);
 }
 
 \f
@@ -7873,23 +9036,42 @@ is_local_forward_loop (const TInsn *insn, fragS *fragP)
 static int
 get_text_align_power (unsigned target_size)
 {
-  int i = 0;
-  unsigned power = 1;
+  if (target_size <= 4)
+    return 2;
 
-  assert (target_size <= INT_MAX);
-  while (target_size > power)
-    {
-      power <<= 1;
-      i += 1;
-    }
-  return i;
+  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);
@@ -7910,14 +9092,14 @@ static int
 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)
     {
@@ -7929,7 +9111,7 @@ get_text_align_fill_size (addressT address,
       /* 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
     {
@@ -7947,7 +9129,7 @@ get_text_align_fill_size (addressT address,
          == (address + fill + target_size - 1) >> align_pow)
        return fill;
     }
-  assert (0);
+  gas_assert (0);
   return 0;
 }
 
@@ -7955,19 +9137,17 @@ get_text_align_fill_size (addressT address,
 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;
 }
@@ -7976,17 +9156,17 @@ branch_align_power (segT sec)
 /* 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)
     {
@@ -7996,7 +9176,7 @@ get_text_align_nop_count (offsetT fill_size, bfd_boolean use_no_density)
       fill_size -= insn_size;
       count++;
     }
-  assert (fill_size != 1);     /* Bad algorithm.  */
+  gas_assert (fill_size != 1); /* Bad algorithm.  */
   return count;
 }
 
@@ -8004,14 +9184,14 @@ get_text_align_nop_count (offsetT fill_size, bfd_boolean use_no_density)
 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)
     {
@@ -8023,7 +9203,7 @@ get_text_align_nth_nop_size (offsetT fill_size,
       if (n + 1 == count)
        return insn_size;
     }
-  assert (0);
+  gas_assert (0);
   return 0;
 }
 
@@ -8055,10 +9235,10 @@ get_noop_aligned_address (fragS *fragP, addressT address)
   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);
@@ -8066,7 +9246,7 @@ get_noop_aligned_address (fragS *fragP, addressT address)
   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);
@@ -8076,21 +9256,16 @@ get_noop_aligned_address (fragS *fragP, addressT address)
      instruction following the loop, not the LOOP instruction.  */
 
   if (first_insn == NULL)
-    return address;
-
-  assert (first_insn->tc_frag_data.is_first_loop_insn);
-
-  first_insn_size = frag_format_size (first_insn);
-
-  if (first_insn_size == 2 || first_insn_size == XTENSA_UNDEFINED)
-    first_insn_size = 3;       /* ISA specifies this */
+    first_insn_size = xtensa_fetch_width;
+  else
+    first_insn_size = get_loop_align_size (frag_format_size (first_insn));
 
   /* If it was 8, then we'll need a larger alignment for the section.  */
   align_power = get_text_align_power (first_insn_size);
   record_alignment (now_seg, align_power);
 
   fill_size = get_text_align_fill_size
-    (address + pre_opcode_bytes, align_power, first_insn_size, TRUE,
+    (address + pre_opcode_bytes, align_power, first_insn_size, true,
      fragP->tc_frag_data.is_no_density);
 
   return address + fill_size;
@@ -8120,12 +9295,13 @@ get_aligned_diff (fragS *fragP, addressT address, offsetT *max_diff)
   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:
@@ -8138,48 +9314,49 @@ get_aligned_diff (fragS *fragP, addressT address, offsetT *max_diff)
       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 = 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);
 
-      if (target_size == 2)
-       target_size = 3; /* ISA specifies this */
-
       /* In an ideal world, which is what we are shooting for here,
         we wouldn't need to use any NOPs immediately prior to the
         LOOP instruction.  If this approach fails, relax_frag_loop_align
         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;
 }
 
@@ -8189,8 +9366,194 @@ get_aligned_diff (fragS *fragP, addressT address, offsetT *max_diff)
 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".  */
@@ -8201,14 +9564,14 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
   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;
@@ -8243,7 +9606,7 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
     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;
@@ -8271,11 +9634,12 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
            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:
@@ -8286,7 +9650,41 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
       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.  */
@@ -8298,6 +9696,11 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
        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"));
     }
@@ -8305,7 +9708,7 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
   /* 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;
     }
 
@@ -8353,7 +9756,7 @@ relax_frag_add_nop (fragS *fragP)
   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)
     {
@@ -8380,7 +9783,7 @@ relax_frag_for_align (fragS *fragP, long stretch)
   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));
@@ -8428,7 +9831,7 @@ find_address_of_next_align_frag (fragS **fragPP,
                                 int *wide_nops,
                                 int *narrow_nops,
                                 int *widens,
-                                bfd_boolean *paddable)
+                                bool *paddable)
 {
   fragS *fragP = *fragPP;
   addressT address = fragP->fr_address;
@@ -8438,7 +9841,7 @@ find_address_of_next_align_frag (fragS **fragPP,
   while (fragP)
     {
       /* Limit this to a small search.  */
-      if (*widens > 8)
+      if (*widens >= (int) xtensa_fetch_width)
        {
          *fragPP = fragP;
          return 0;
@@ -8452,7 +9855,7 @@ find_address_of_next_align_frag (fragS **fragPP,
          switch (fragP->fr_subtype)
            {
            case RELAX_UNREACHABLE:
-             *paddable = TRUE;
+             *paddable = true;
              break;
 
            case RELAX_FILL_NOP:
@@ -8467,7 +9870,7 @@ find_address_of_next_align_frag (fragS **fragPP,
                  (*widens)++;
                  break;
                }
-             address += total_frag_text_expansion (fragP);;
+             address += total_frag_text_expansion (fragP);
              break;
 
            case RELAX_IMMED:
@@ -8514,7 +9917,7 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
   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;
@@ -8525,12 +9928,19 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
   address = find_address_of_next_align_frag
     (&fragP, &wide_nops, &narrow_nops, &num_widens, &paddable);
 
-  if (address)
+  if (!address)
+    {
+      if (this_frag->tc_frag_data.is_aligning_branch)
+       this_frag->tc_frag_data.slot_subtypes[0] = RELAX_IMMED;
+      else
+       frag_wane (this_frag);
+    }
+  else
     {
       local_opt_diff = get_aligned_diff (fragP, address, &max_diff);
       opt_diff = local_opt_diff;
-      assert (opt_diff >= 0);
-      assert (max_diff >= opt_diff);
+      gas_assert (opt_diff >= 0);
+      gas_assert (max_diff >= opt_diff);
       if (max_diff == 0)
        return 0;
 
@@ -8545,12 +9955,12 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
          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 (glob_pad || glob_widens >= (1 << branch_align_power (now_seg)))
-           break;
+           address = 0;
 
          if (address)
            {
@@ -8588,7 +9998,7 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
        {
          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;
@@ -8610,13 +10020,13 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
 
       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;
@@ -8626,172 +10036,237 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
 /* 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
+
+*/
+
+static long
+bytes_to_stretch (fragS *this_frag,
+                 int wide_nops,
+                 int narrow_nops,
+                 int num_widens,
+                 int desired_diff)
+{
+  int nops_needed;
+  int nop_bytes;
+  int extra_bytes;
+  int bytes_short = desired_diff - num_widens;
+
+  gas_assert (desired_diff >= 0
+             && desired_diff < (signed) xtensa_fetch_width);
+  if (desired_diff == 0)
+    return 0;
+
+  gas_assert (wide_nops > 0 || num_widens > 0);
+
+  /* Always prefer widening to NOP-filling.  */
+  if (bytes_short < 0)
+    {
+      /* There are enough RELAX_NARROW frags after this one
+        to align the target without widening this frag in any way.  */
+      return 0;
+    }
+
+  if (bytes_short == 0)
+    {
+      /* Widen every narrow between here and the align target
+        and the align target will be properly aligned.  */
+      if (this_frag->fr_subtype == RELAX_FILL_NOP)
+       return 0;
+      else
+       return 1;
+    }
+
+  /* From here we will need at least one NOP to get an alignment.
+     However, we may not be able to align at all, in which case,
+     don't widen.  */
+  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)
+    {
+      if (this_frag->fr_subtype == RELAX_FILL_NOP)
+       return 3;
+      else if (num_widens == extra_bytes)
+       return 1;
+      return 0;
+    }
+
+  /* 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)
+    {
+      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;
+    }
+
+  /* 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;
+      }
 
-   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
+  gas_assert (slot >= 0 && slot < MAX_SLOTS);
 
-   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 unneccesary)
-    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)
-*/
+  return slot;
+}
 
-static long
-bytes_to_stretch (fragS *this_frag,
-                 int wide_nops,
-                 int narrow_nops,
-                 int num_widens,
-                 int desired_diff)
+static fixS *
+add_jump_to_trampoline (fragS *tramp, fragS *origfrag)
 {
-  int bytes_short = desired_diff - num_widens;
-
-  assert (desired_diff >= 0 && desired_diff < 8);
-  if (desired_diff == 0)
-    return 0;
+  int slot = xg_get_single_symbol_slot (origfrag);
+  fixS *fixP;
 
-  assert (wide_nops > 0 || num_widens > 0);
+  /* 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]);
 
-  /* Always prefer widening to NOP-filling.  */
-  if (bytes_short < 0)
-    {
-      /* There are enough RELAX_NARROW frags after this one
-        to align the target without widening this frag in any way.  */
-      return 0;
-    }
+  /* 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 (bytes_short == 0)
+  /* If trampoline is full, remove it from the list.  */
+  if (xg_is_trampoline_frag_full (tramp))
     {
-      /* Widen every narrow between here and the align target
-        and the align target will be properly aligned.  */
-      if (this_frag->fr_subtype == RELAX_FILL_NOP)
-       return 0;
-      else
-       return 1;
-    }
+      struct trampoline_seg *ts = find_trampoline_seg (now_seg);
+      size_t tr = xg_find_trampoline (&ts->index, tramp->fr_address);
 
-  /* 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)
-    {
-      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);
-       }
+      gas_assert (ts->index.entry[tr] == tramp);
+      xg_remove_trampoline_from_index (&ts->index, tr);
     }
-  else
-    {
-      /* We will need a NOP no matter what, but should we widen
-        this instruction to help?
 
-        This is a RELAX_FRAG_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;
-       }
-    }
-  assert (0);
-  return 0;
+  return fixP;
 }
 
 
@@ -8803,33 +10278,31 @@ relax_frag_immed (segT segP,
                  xtensa_format fmt,
                  int slot,
                  int *stretched_p,
-                 bfd_boolean estimate_only)
+                 bool estimate_only)
 {
   TInsn tinsn;
-  vliw_insn orig_vinsn;
   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_init_vinsn (&orig_vinsn);
-  vinsn_from_chars (&orig_vinsn, fragP->fr_opcode);
-  if (xtensa_format_num_slots (isa, fmt) > 1)
-    wide_insn = TRUE;
+  xg_clear_vinsn (&cur_vinsn);
+  vinsn_from_chars (&cur_vinsn, fragP->fr_opcode);
+  if (cur_vinsn.num_slots > 1)
+    from_wide_insn = true;
 
-  tinsn = orig_vinsn.slots[slot];
+  tinsn = cur_vinsn.slots[slot];
   tinsn_immed_from_frag (&tinsn, fragP, slot);
 
-  if (estimate_only && xtensa_opcode_is_loop (isa, tinsn.opcode))
+  if (estimate_only && xtensa_opcode_is_loop (isa, tinsn.opcode) == 1)
     return 0;
 
   if (workaround_b_j_loop_end && ! fragP->tc_frag_data.is_no_transform)
@@ -8856,60 +10329,73 @@ relax_frag_immed (segT segP,
   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;
 
@@ -8922,6 +10408,64 @@ relax_frag_immed (segT segP,
   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;
 }
 
@@ -8941,10 +10485,10 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp)
   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)
@@ -8982,6 +10526,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp)
            case RELAX_IMMED:
            case RELAX_IMMED_STEP1:
            case RELAX_IMMED_STEP2:
+           case RELAX_IMMED_STEP3:
              /* Place the immediate.  */
              convert_frag_immed
                (sec, fragp,
@@ -9031,7 +10576,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *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;
@@ -9041,6 +10586,9 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp)
       else
        as_bad (_("invalid relaxation fragment result"));
       break;
+
+    case RELAX_TRAMPOLINE:
+      break;
     }
 
   fragp->fr_var = 0;
@@ -9052,7 +10600,7 @@ static void
 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;
@@ -9081,16 +10629,15 @@ static void
 convert_frag_narrow (segT segP, fragS *fragP, xtensa_format fmt, int slot)
 {
   TInsn tinsn, single_target;
-  xtensa_format single_fmt;
   int size, old_size, diff;
   offsetT frag_offset;
 
-  assert (slot == 0);
+  gas_assert (slot == 0);
   tinsn_from_chars (&tinsn, fragP->fr_opcode, 0);
 
-  if (xtensa_opcode_is_branch (xtensa_default_isa, tinsn.opcode) == 1)
+  if (fragP->tc_frag_data.is_aligning_branch == 1)
     {
-      assert (fragP->tc_frag_data.text_expansion[0] == 1
+      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);
@@ -9104,7 +10651,7 @@ convert_frag_narrow (segT segP, fragS *fragP, xtensa_format fmt, int slot)
       return;
     }
 
-  assert (fragP->fr_opcode != NULL);
+  gas_assert (fragP->fr_opcode != NULL);
 
   /* Frags in this relaxation state should only contain
      single instruction bundles.  */
@@ -9117,21 +10664,19 @@ convert_frag_narrow (segT segP, fragS *fragP, xtensa_format fmt, int slot)
   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);
-  single_fmt = xg_get_single_format (single_target.opcode);
-
-  xg_emit_insn_to_buf (&single_target, single_fmt, fragP->fr_opcode,
-                      fragP, frag_offset, TRUE);
+  xg_emit_insn_to_buf (&single_target, fragP->fr_opcode, fragP,
+                      frag_offset, true);
 
   diff = size - old_size;
-  assert (diff >= 0);
-  assert (diff <= fragP->fr_var);
+  gas_assert (diff >= 0);
+  gas_assert (diff <= fragP->fr_var);
   fragP->fr_var -= diff;
   fragP->fr_fix += diff;
 
@@ -9145,7 +10690,7 @@ convert_frag_fill_nop (fragS *fragP)
 {
   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)
     {
@@ -9154,7 +10699,7 @@ convert_frag_fill_nop (fragS *fragP)
       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);
@@ -9164,7 +10709,6 @@ convert_frag_fill_nop (fragS *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,
@@ -9175,24 +10719,23 @@ 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;
-  vliw_insn orig_vinsn;
   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_init_vinsn (&orig_vinsn);
+  xg_clear_vinsn (&cur_vinsn);
 
-  vinsn_from_chars (&orig_vinsn, fr_opcode);
-  if (xtensa_format_num_slots (isa, fmt) > 1)
-    wide_insn = TRUE;
+  vinsn_from_chars (&cur_vinsn, fr_opcode);
+  if (cur_vinsn.num_slots > 1)
+    from_wide_insn = true;
 
-  orig_tinsn = orig_vinsn.slots[slot];
+  orig_tinsn = cur_vinsn.slots[slot];
   tinsn_immed_from_frag (&orig_tinsn, fragP, slot);
 
   is_loop = xtensa_opcode_is_loop (xtensa_default_isa, orig_tinsn.opcode) == 1;
@@ -9206,20 +10749,20 @@ convert_frag_immed (segT segP,
       bytes = xtensa_format_length (isa, fmt);
       if (bytes >= 4)
        {
-         orig_vinsn.slots[slot].opcode =
-           xtensa_format_slot_nop_opcode (isa, orig_vinsn.format, slot);
-         orig_vinsn.slots[slot].ntok = 0;
+         cur_vinsn.slots[slot].opcode =
+           xtensa_format_slot_nop_opcode (isa, cur_vinsn.format, slot);
+         cur_vinsn.slots[slot].ntok = 0;
        }
       else
        {
          bytes += fragP->tc_frag_data.text_expansion[0];
-         assert (bytes == 2 || bytes == 3);
-         build_nop (&orig_vinsn.slots[0], bytes);
+         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 (&orig_vinsn, fr_opcode, frag_now, FALSE);
+      vinsn_to_insnbuf (&cur_vinsn, fr_opcode, frag_now, true);
       xtensa_insnbuf_to_chars
-       (isa, orig_vinsn.insnbuf, (unsigned char *) fr_opcode, 0);
+       (isa, cur_vinsn.insnbuf, (unsigned char *) fr_opcode, 0);
       fragP->fr_var = 0;
     }
   else
@@ -9237,8 +10780,7 @@ convert_frag_immed (segT segP,
       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.  */
@@ -9285,23 +10827,23 @@ convert_frag_immed (segT segP,
                      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);
                }
@@ -9312,8 +10854,7 @@ convert_frag_immed (segT segP,
        }
 
       total_size = 0;
-      first = TRUE;
-      last_is_jump = FALSE;
+      first = true;
       for (i = 0; i < istack.ninsn; i++)
        {
          TInsn *tinsn = &istack.insn[i];
@@ -9327,18 +10868,15 @@ convert_frag_immed (segT segP,
            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);
-             if (tinsn->tok[0].X_op == O_pltrel)
-               reloc_type = BFD_RELOC_XTENSA_PLT;
-             else
-               reloc_type = BFD_RELOC_32;
+             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:
@@ -9347,45 +10885,37 @@ convert_frag_immed (segT segP,
            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))
                    {
-                     tinsn->record_fix = TRUE;
-                     orig_vinsn.slots[slot] = *tinsn;
+                     cur_vinsn.slots[slot] = *tinsn;
                    }
                  else
                    {
-                     orig_vinsn.slots[slot].opcode =
+                     cur_vinsn.slots[slot].opcode =
                        xtensa_format_slot_nop_opcode (isa, fmt, slot);
-                     orig_vinsn.slots[slot].ntok = 0;
-                     orig_vinsn.slots[slot].record_fix = FALSE;
+                     cur_vinsn.slots[slot].ntok = 0;
                    }
-                 vinsn_to_insnbuf (&orig_vinsn, immed_instr, fragP, TRUE);
-                 xtensa_insnbuf_to_chars (isa, orig_vinsn.insnbuf,
+                 vinsn_to_insnbuf (&cur_vinsn, immed_instr, fragP, true);
+                 xtensa_insnbuf_to_chars (isa, cur_vinsn.insnbuf,
                                           (unsigned char *) immed_instr, 0);
-                 fragP->tc_frag_data.is_insn = TRUE;
+                 fragP->tc_frag_data.is_insn = true;
                  size = xtensa_format_length (isa, fmt);
                  if (!opcode_fits_format_slot (tinsn->opcode, fmt, slot))
                    {
-                     xtensa_format single_fmt =
-                       xg_get_single_format (tinsn->opcode);
-
                      xg_emit_insn_to_buf
-                       (tinsn, single_fmt, immed_instr + size, fragP,
-                        immed_instr - fragP->fr_literal + size, TRUE);
+                       (tinsn, immed_instr + size, fragP,
+                        immed_instr - fragP->fr_literal + size, true);
                      size += xg_get_single_size (tinsn->opcode);
                    }
                }
              else
                {
-                 xtensa_format single_format;
                  size = xg_get_single_size (tinsn->opcode);
-                 single_format = xg_get_single_format (tinsn->opcode);
-                 xg_emit_insn_to_buf (tinsn, single_format, immed_instr,
-                                      fragP,
-                                      immed_instr - fragP->fr_literal, TRUE);
+                 xg_emit_insn_to_buf (tinsn, immed_instr, fragP,
+                                      immed_instr - fragP->fr_literal, true);
                }
              immed_instr += size;
              total_size += size;
@@ -9394,17 +10924,14 @@ convert_frag_immed (segT segP,
        }
 
       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;
     }
 
-  /* Clean it up.  */
-  xg_free_vinsn (&orig_vinsn);
-
   /* Check for undefined immediates in LOOP instructions.  */
   if (is_loop)
     {
@@ -9423,14 +10950,11 @@ convert_frag_immed (segT segP,
        }
     }
 
-  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);
     }
 }
@@ -9453,7 +10977,7 @@ fix_new_exp_in_seg (segT new_seg,
   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);
@@ -9462,127 +10986,6 @@ fix_new_exp_in_seg (segT new_seg,
 }
 
 
-/* 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;
-    }
-
-  know (symbolP);
-  know (symbolP->sy_frag);
-  know (!(S_GET_SEGMENT (symbolP) == absolute_section)
-       || symbol_get_frag (symbolP) == &zero_address_frag);
-
-  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
@@ -9623,7 +11026,7 @@ get_subseg_info (segT seg, subsegT subseg)
 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;
@@ -9651,7 +11054,7 @@ static void
 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)
@@ -9705,7 +11108,7 @@ xtensa_move_seg_list_to_beginning (seg_list *head)
       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);
@@ -9718,42 +11121,214 @@ xtensa_move_seg_list_to_beginning (seg_list *head)
 
 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);
-  mark_literal_frags (init_literal_head->next);
-  mark_literal_frags (fini_literal_head->next);
 
   if (use_literal_section)
     return;
 
-  segment = literal_head->next;
-  while (segment)
+  /* 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 ((!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;
       search_frag = frchain_from->frch_root;
       literal_pool = NULL;
       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);
 
@@ -9763,34 +11338,75 @@ xtensa_move_literals (void)
         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);
            }
-         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_fill && search_frag->fr_fix == 0)
+           {
+             /* Skip empty fill frags.  */
+             *frag_splice = next_frag;
+             search_frag = next_frag;
+             continue;
+           }
+
+         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.  */
@@ -9819,20 +11435,19 @@ xtensa_move_literals (void)
          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);
-      segment = segment->next;
     }
 
   /* Now fix up the SEGMENT value for all the literal symbols.  */
   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);
     }
 }
 
@@ -9853,7 +11468,7 @@ mark_literal_frags (seg_list *segment)
       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;
@@ -9873,7 +11488,7 @@ xtensa_reorder_seg_list (seg_list *head, segT after)
       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);
@@ -9904,13 +11519,11 @@ xtensa_reorder_segments (void)
   /* Now that we have the last section, push all the literal
      sections to the end.  */
   xtensa_reorder_seg_list (literal_head, last_sec);
-  xtensa_reorder_seg_list (init_literal_head, last_sec);
-  xtensa_reorder_seg_list (fini_literal_head, last_sec);
 
   /* 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);
 }
 
 
@@ -9923,10 +11536,8 @@ xtensa_switch_to_literal_fragment (emit_state *result)
 {
   if (directive_state[directive_absolute_literals])
     {
-      cache_literal_section (0, default_lit_sections.lit4_seg_name,
-                            &default_lit_sections.lit4_seg, FALSE);
-      xtensa_switch_section_emit_state (result,
-                                       default_lit_sections.lit4_seg, 0);
+      segT lit4_seg = cache_literal_section (true);
+      xtensa_switch_section_emit_state (result, lit4_seg, 0);
     }
   else
     xtensa_switch_to_non_abs_literal_fragment (result);
@@ -9939,63 +11550,28 @@ xtensa_switch_to_literal_fragment (emit_state *result)
 
 static void
 xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
-{
-  /* 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.  */
-
-  static bfd_boolean recursive = FALSE;
-  fragS *pool_location = get_literal_pool_location (now_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));
-
-  if (pool_location == NULL
-      && !use_literal_section
-      && !recursive
-      && !is_init && ! is_fini)
-    {
-      as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
-      recursive = TRUE;
-      xtensa_mark_literal_pool_location ();
-      recursive = FALSE;
-    }
-
-  /* Special case: If we are in the ".fini" or ".init" section, then
-     we will ALWAYS be generating to the ".fini.literal" and
-     ".init.literal" sections.  */
-
-  if (is_init)
-    {
-      cache_literal_section (init_literal_head,
-                            default_lit_sections.init_lit_seg_name,
-                            &default_lit_sections.init_lit_seg, TRUE);
-      xtensa_switch_section_emit_state (result,
-                                       default_lit_sections.init_lit_seg, 0);
-    }
-  else if (is_fini)
-    {
-      cache_literal_section (fini_literal_head,
-                            default_lit_sections.fini_lit_seg_name,
-                            &default_lit_sections.fini_lit_seg, TRUE);
-      xtensa_switch_section_emit_state (result,
-                                       default_lit_sections.fini_lit_seg, 0);
-    }
-  else
+{
+  fragS *pool_location = get_literal_pool_location (now_seg);
+  segT lit_seg;
+  bool is_init_fini = xtensa_is_init_fini (now_seg);
+
+  if (pool_location == NULL
+      && !use_literal_section
+      && !is_init_fini)
     {
-      cache_literal_section (literal_head,
-                            default_lit_sections.lit_seg_name,
-                            &default_lit_sections.lit_seg, TRUE);
-      xtensa_switch_section_emit_state (result,
-                                       default_lit_sections.lit_seg, 0);
+      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);
+  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.  */
@@ -10036,49 +11612,135 @@ xtensa_restore_emit_state (emit_state *state)
 }
 
 
-/* Get a segment of a given name.  If the segment is already
-   present, return it; otherwise, create a new one.  */
+/* Predicate function used to look up a section in a particular group.  */
 
-static void
-cache_literal_section (seg_list *head,
-                      const char *name,
-                      segT *pseg,
-                      bfd_boolean is_code)
+static bool
+match_section_group (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
 {
-  segT current_section = now_seg;
-  int current_subsec = now_subseg;
-  segT seg;
+  const char *gname = inf;
+  const char *group_name = elf_group_name (sec);
+
+  return (group_name == gname
+         || (group_name != NULL
+             && gname != NULL
+             && strcmp (group_name, gname) == 0));
+}
 
-  if (*pseg != 0)
-    return;
 
-  /* Check if the named section exists.  */
-  for (seg = stdoutput->sections; seg; seg = seg->next)
+/* Get the literal section to be used for the current text section.
+   The result may be cached in the default_lit_sections structure.  */
+
+static segT
+cache_literal_section (bool use_abs_literals)
+{
+  const char *text_name, *group_name = 0;
+  const char *base_name, *suffix;
+  char *name;
+  segT *pcached;
+  segT seg, current_section;
+  int current_subsec;
+  bool linkonce = false;
+
+  /* Save the current section/subsection.  */
+  current_section = now_seg;
+  current_subsec = now_subseg;
+
+  /* Clear the cached values if they are no longer valid.  */
+  if (now_seg != default_lit_sections.current_text_seg)
     {
-      if (!strcmp (segment_name (seg), name))
-       break;
+      default_lit_sections.current_text_seg = now_seg;
+      default_lit_sections.lit_seg = NULL;
+      default_lit_sections.lit4_seg = NULL;
     }
 
-  if (!seg)
+  /* Check if the literal section is already cached.  */
+  if (use_abs_literals)
+    pcached = &default_lit_sections.lit4_seg;
+  else
+    pcached = &default_lit_sections.lit_seg;
+
+  if (*pcached)
+    return *pcached;
+
+  text_name = default_lit_sections.lit_prefix;
+  if (! text_name || ! *text_name)
+    {
+      text_name = segment_name (current_section);
+      group_name = elf_group_name (current_section);
+      linkonce = (current_section->flags & SEC_LINK_ONCE) != 0;
+    }
+
+  base_name = use_abs_literals ? ".lit4" : ".literal";
+  if (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 = concat (".gnu.linkonce", base_name, suffix ? suffix : "",
+                    (char *) NULL);
+      linkonce = true;
+    }
+  else
+    {
+      /* 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
+             || startswith (text_name, ".text")))
+       len -= 5;
+
+      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.
+     The group name, if any, came from the current text section and
+     has already been canonicalized.  */
+  name = tc_canonicalize_symbol_name (name);
+
+  seg = bfd_get_section_by_name_if (stdoutput, name, match_section_group,
+                                   (void *) group_name);
+  if (! seg)
     {
-      /* Create a new literal section.  */
-      seg = subseg_new (name, (subsegT) 0);
-      if (head)
+      flagword flags;
+
+      seg = subseg_force_new (name, 0);
+
+      if (! use_abs_literals)
        {
-         /* Add the newly created literal segment to the specified list.  */
-         seg_list *n = (seg_list *) xmalloc (sizeof (seg_list));
+         /* Add the newly created literal segment to the list.  */
+         seg_list *n = XNEW (seg_list);
          n->seg = seg;
-         n->next = head->next;
-         head->next = n;
+         n->next = literal_head->next;
+         literal_head->next = n;
        }
-      bfd_set_section_flags (stdoutput, seg, SEC_HAS_CONTENTS |
-                            SEC_READONLY | SEC_ALLOC | SEC_LOAD
-                            | (is_code ? SEC_CODE : SEC_DATA));
-      bfd_set_section_alignment (stdoutput, seg, 2);
+
+      flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_ALLOC | SEC_LOAD
+              | (linkonce ? (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD) : 0)
+              | (use_abs_literals ? SEC_DATA : SEC_CODE));
+
+      elf_group_name (seg) = group_name;
+
+      bfd_set_section_flags (seg, flags);
+      bfd_set_section_alignment (seg, 2);
     }
 
-  *pseg = seg;
+  *pcached = seg;
   subseg_set (current_section, current_subsec);
+  return seg;
 }
 
 \f
@@ -10088,26 +11750,24 @@ cache_literal_section (seg_list *head,
 #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 segT retrieve_xtensa_section (char *);
-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.  */
 
@@ -10115,16 +11775,15 @@ void
 xtensa_post_relax_hook (void)
 {
   xtensa_move_seg_list_to_beginning (literal_head);
-  xtensa_move_seg_list_to_beginning (init_literal_head);
-  xtensa_move_seg_list_to_beginning (fini_literal_head);
 
   xtensa_find_unmarked_state_frags ();
+  xtensa_mark_frags_for_org ();
+  xtensa_mark_difference_of_two_symbols ();
 
-  if (use_literal_section)
-    xtensa_create_property_segments (get_frag_is_literal,
-                                    NULL,
-                                    XTENSA_LIT_SEC_NAME,
-                                    xt_literal_sec);
+  xtensa_create_property_segments (get_frag_is_literal,
+                                  NULL,
+                                  XTENSA_LIT_SEC_NAME,
+                                  xt_literal_sec);
   xtensa_create_xproperty_segments (get_frag_property_flags,
                                    XTENSA_PROP_SEC_NAME,
                                    xt_prop_sec);
@@ -10137,10 +11796,10 @@ xtensa_post_relax_hook (void)
 
 /* 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;
 }
 
@@ -10163,24 +11822,23 @@ xtensa_create_property_segments (frag_predicate property_function,
        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))
        {
-         char *property_section_name =
-           xtensa_get_property_section_name (sec, section_name_base);
-         segT insn_sec = retrieve_xtensa_section (property_section_name);
-         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);
        }
     }
@@ -10201,7 +11859,6 @@ xtensa_create_property_segments (frag_predicate 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;
 
@@ -10209,70 +11866,37 @@ xtensa_create_property_segments (frag_predicate property_function,
            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);
            }
        }
     }
@@ -10296,24 +11920,23 @@ xtensa_create_xproperty_segments (frag_flags_fn flag_fn,
        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))
        {
-         char *property_section_name =
-           xtensa_get_property_section_name (sec, section_name_base);
-         segT insn_sec = retrieve_xtensa_section (property_section_name);
-         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);
        }
     }
 
@@ -10333,7 +11956,6 @@ xtensa_create_xproperty_segments (frag_flags_fn 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;
 
@@ -10341,142 +11963,69 @@ xtensa_create_xproperty_segments (frag_flags_fn flag_fn,
            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)
-{
-  segment_info_type *seginfo;
-  seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
-  if (!seginfo)
-    {
-      frchainS *frchainP;
-
-      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);
-
-      frchainP = (frchainS *) xmalloc (sizeof (frchainS));
-      frchainP->frch_root = NULL;
-      frchainP->frch_last = NULL;
-      frchainP->frch_next = NULL;
-      frchainP->frch_seg = seg;
-      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;
-    }
-
-  return seginfo;
-}
-
-
-static segT
-retrieve_xtensa_section (char *sec_name)
+static bool
+exclude_section_from_property_tables (segT sec)
 {
-  bfd *abfd = stdoutput;
-  flagword flags, out_flags, link_once_flags;
-  segT s;
+  flagword flags = bfd_section_flags (sec);
 
-  flags = bfd_get_section_flags (abfd, now_seg);
-  link_once_flags = (flags & SEC_LINK_ONCE);
-  if (link_once_flags)
-    link_once_flags |= (flags & SEC_LINK_DUPLICATES);
-  out_flags = (SEC_RELOC | SEC_HAS_CONTENTS | SEC_READONLY | link_once_flags);
+  /* Sections that don't contribute to the memory footprint are excluded.  */
+  if ((flags & SEC_DEBUGGING)
+      || !(flags & SEC_ALLOC)
+      || (flags & SEC_MERGE))
+    return true;
 
-  s = bfd_make_section_old_way (abfd, sec_name);
-  if (s == NULL)
-    as_bad (_("could not create section %s"), sec_name);
-  if (!bfd_set_section_flags (abfd, s, out_flags))
-    as_bad (_("invalid flag combination on section %s"), sec_name);
+  /* 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 s;
+  return false;
 }
 
 
-static bfd_boolean
+static bool
 section_has_property (segT sec, frag_predicate property_function)
 {
   segment_info_type *seginfo = seg_info (sec);
@@ -10488,14 +12037,14 @@ section_has_property (segT sec, frag_predicate property_function)
        {
          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);
@@ -10508,10 +12057,10 @@ section_has_xproperty (segT sec, frag_flags_fn property_function)
          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;
 }
 
 
@@ -10519,30 +12068,21 @@ section_has_xproperty (segT sec, frag_flags_fn property_function)
 
 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)
        {
@@ -10559,8 +12099,7 @@ add_xt_block_frags (segT sec,
                }
              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;
@@ -10581,15 +12120,15 @@ add_xt_block_frags (segT sec,
 
 /* 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;
 }
 
 
@@ -10605,38 +12144,42 @@ get_frag_property_flags (const fragS *fragP, frag_flags *prop_flags)
 {
   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;
+      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;
-      if (fragP->tc_frag_data.is_specific_opcode
-         || fragP->tc_frag_data.is_no_transform)
-       prop_flags->insn.is_no_transform = 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)
@@ -10655,8 +12198,8 @@ frag_flags_to_number (const frag_flags *prop_flags)
 
   if (prop_flags->insn.is_no_density)
     num |= XTENSA_PROP_INSN_NO_DENSITY;
-  if (prop_flags->insn.is_no_transform)
-    num |= XTENSA_PROP_INSN_NO_TRANSFORM;
+  if (prop_flags->is_no_transform)
+    num |= XTENSA_PROP_NO_TRANSFORM;
   if (prop_flags->insn.is_no_reorder)
     num |= XTENSA_PROP_INSN_NO_REORDER;
   if (prop_flags->insn.is_abslit)
@@ -10672,44 +12215,44 @@ frag_flags_to_number (const frag_flags *prop_flags)
 }
 
 
-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;
-      if (prop_flags_1->insn.is_no_transform !=
-         prop_flags_2->insn.is_no_transform)
-       return FALSE;
+       return false;
+      if (prop_flags_1->is_no_transform !=
+         prop_flags_2->is_no_transform)
+       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;
 }
 
 
@@ -10729,15 +12272,15 @@ xt_block_aligned_size (const xtensa_block_info *xt_block)
 }
 
 
-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
@@ -10748,7 +12291,7 @@ xtensa_xt_block_combine (xtensa_block_info *xt_block,
        {
          /* Nothing needed.  */
          if (xt_block->flags.alignment >= xt_block_2->flags.alignment)
-           return TRUE;
+           return true;
        }
       else
        {
@@ -10758,38 +12301,32 @@ xtensa_xt_block_combine (xtensa_block_info *xt_block,
              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)
     {
@@ -10798,11 +12335,9 @@ add_xt_prop_frags (segT sec,
   /* 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;
@@ -10821,8 +12356,7 @@ add_xt_prop_frags (segT sec,
                  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;
                }
@@ -10847,22 +12381,18 @@ init_op_placement_info_table (void)
   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->single = XTENSA_UNDEFINED;
-      opi->single_size = 0;
-      opi->widest = XTENSA_UNDEFINED;
-      opi->widest_size = 0;
       opi->narrowest = XTENSA_UNDEFINED;
       opi->narrowest_size = 0x7F;
+      opi->narrowest_slot = 0;
       opi->formats = 0;
       opi->num_formats = 0;
       opi->issuef = 0;
@@ -10877,25 +12407,15 @@ init_op_placement_info_table (void)
                  opi->issuef++;
                  set_bit (fmt, opi->formats);
                  set_bit (slot, opi->slots[fmt]);
-                 /* opi->slot_count[fmt]++; */
-                 if (fmt_length < opi->narrowest_size)
+                 if (fmt_length < opi->narrowest_size
+                     || (fmt_length == opi->narrowest_size
+                         && (xtensa_format_num_slots (isa, fmt)
+                             < xtensa_format_num_slots (isa,
+                                                        opi->narrowest))))
                    {
                      opi->narrowest = fmt;
                      opi->narrowest_size = fmt_length;
-                   }
-                 if (fmt_length > opi->widest_size)
-                   {
-                     opi->widest = fmt;
-                     opi->widest_size = fmt_length;
-                   }
-                 if (xtensa_format_num_slots (isa, fmt) == 1)
-                   {
-                     if (opi->single_size == 0
-                         || fmt_length < opi->single_size)
-                       {
-                         opi->single = fmt;
-                         opi->single_size = fmt_length;
-                       }
+                     opi->narrowest_slot = slot;
                    }
                }
            }
@@ -10907,7 +12427,7 @@ init_op_placement_info_table (void)
 }
 
 
-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]);
@@ -10919,15 +12439,21 @@ opcode_fits_format_slot (xtensa_opcode opcode, xtensa_format fmt, int slot)
 static int
 xg_get_single_size (xtensa_opcode opcode)
 {
-  assert (op_placement_table[opcode].single != XTENSA_UNDEFINED);
-  return op_placement_table[opcode].single_size;
+  return op_placement_table[opcode].narrowest_size;
 }
 
 
 static xtensa_format
 xg_get_single_format (xtensa_opcode opcode)
 {
-  return op_placement_table[opcode].single;
+  return op_placement_table[opcode].narrowest;
+}
+
+
+static int
+xg_get_single_slot (xtensa_opcode opcode)
+{
+  return op_placement_table[opcode].narrowest_slot;
 }
 
 \f
@@ -10936,19 +12462,18 @@ xg_get_single_format (xtensa_opcode opcode)
 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);
@@ -10962,7 +12487,7 @@ TInsn *
 istack_top (IStack *stack)
 {
   int rec = stack->ninsn - 1;
-  assert (!istack_empty (stack));
+  gas_assert (!istack_empty (stack));
   return &stack->insn[rec];
 }
 
@@ -10974,7 +12499,7 @@ void
 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++;
 }
@@ -10988,9 +12513,9 @@ istack_push_space (IStack *stack)
 {
   int rec = stack->ninsn;
   TInsn *insn;
-  assert (!istack_full (stack));
+  gas_assert (!istack_full (stack));
   insn = &stack->insn[rec];
-  memset (insn, 0, sizeof (TInsn));
+  tinsn_init (insn);
   stack->ninsn++;
   return insn;
 }
@@ -11003,9 +12528,9 @@ void
 istack_pop (IStack *stack)
 {
   int rec = stack->ninsn - 1;
-  assert (!istack_empty (stack));
+  gas_assert (!istack_empty (stack));
   stack->ninsn--;
-  memset (&stack->insn[rec], 0, sizeof (TInsn));
+  tinsn_init (&stack->insn[rec]);
 }
 
 \f
@@ -11018,26 +12543,15 @@ tinsn_init (TInsn *dst)
 }
 
 
-/* Get the ``num''th token of the TInsn.
-   It is illegal to call this if num > insn->ntoks.  */
-
-expressionS *
-tinsn_get_tok (TInsn *insn, int num)
-{
-  assert (num < insn->ntok);
-  return &insn->tok[num];
-}
-
-
 /* 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)
     {
@@ -11047,21 +12561,21 @@ tinsn_has_symbolic_operands (const TInsn *insn)
        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)
     {
@@ -11080,23 +12594,17 @@ tinsn_has_invalid_symbolic_operands (const TInsn *insn)
        default:
          /* Symbolic immediates are only allowed on the last immediate
             operand.  At this time, CONST16 is the only opcode where we
-            support non-PC-relative relocations.  (It isn't necessary
-            to complain about non-PC-relative relocations here, but
-            otherwise, no error is reported until the relocations are
-            generated, and the assembler won't get that far if there
-            are any other errors.  It's nice to see all the problems
-            at once.)  */
+            support non-PC-relative relocations.  */
          if (i != get_relaxable_immed (insn->opcode)
              || (xtensa_operand_is_PCrelative (isa, insn->opcode, i) != 1
                  && insn->opcode != xtensa_const16_opcode))
            {
-             as_bad (_("invalid symbolic operand %d on '%s'"),
-                     i, xtensa_opcode_name (isa, insn->opcode));
-             return TRUE;
+             as_bad (_("invalid symbolic operand"));
+             return true;
            }
        }
     }
-  return FALSE;
+  return false;
 }
 
 
@@ -11106,12 +12614,12 @@ tinsn_has_invalid_symbolic_operands (const TInsn *insn)
    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)
@@ -11123,101 +12631,22 @@ tinsn_has_complex_operands (const TInsn *insn)
        case O_hi16:
          break;
        default:
-         return TRUE;
-       }
-    }
-  return FALSE;
-}
-
-
-/* Convert the constant operands in the tinsn to insnbuf.
-   Return TRUE if there is a symbol in the immediate field.
-
-   Before this is called,
-   1) the number of operands are correct
-   2) the tinsn is a ITYPE_INSN
-   3) ONLY the relaxable_ is built
-   4) All operands are O_constant, O_symbol.  All constants fit
-   The return value tells whether there are any remaining O_symbols.  */
-
-static bfd_boolean
-tinsn_to_insnbuf (TInsn *tinsn, xtensa_insnbuf insnbuf)
-{
-  static xtensa_insnbuf slotbuf = 0;
-  xtensa_isa isa = xtensa_default_isa;
-  xtensa_opcode opcode = tinsn->opcode;
-  xtensa_format fmt = xg_get_single_format (opcode);
-  bfd_boolean has_fixup = FALSE;
-  int noperands = xtensa_opcode_num_operands (isa, opcode);
-  int i;
-  uint32 opnd_value;
-  char *file_name;
-  unsigned line;
-
-  if (!slotbuf)
-    slotbuf = xtensa_insnbuf_alloc (isa);
-
-  assert (tinsn->insn_type == ITYPE_INSN);
-  if (noperands != tinsn->ntok)
-    as_fatal (_("operand number mismatch"));
-
-  if (xtensa_opcode_encode (isa, fmt, 0, slotbuf, opcode))
-    as_fatal (_("cannot encode opcode"));
-
-  for (i = 0; i < noperands; ++i)
-    {
-      expressionS *expr = &tinsn->tok[i];
-      switch (expr->X_op)
-       {
-       case O_register:
-         if (xtensa_operand_is_visible (isa, opcode, i) == 0)
-           break;
-         /* The register number has already been checked in
-            expression_maybe_register, so we don't need to check here.  */
-         opnd_value = expr->X_add_number;
-         (void) xtensa_operand_encode (isa, opcode, i, &opnd_value);
-         xtensa_operand_set_field (isa, opcode, i, fmt, 0,
-                                   slotbuf, opnd_value);
-         break;
-
-       case O_constant:
-         if (xtensa_operand_is_visible (isa, opcode, i) == 0)
-           break;
-         as_where (&file_name, &line);
-         /* It is a constant and we called this function,
-            then we have to try to fit it.  */
-         xtensa_insnbuf_set_operand (slotbuf, fmt, 0, opcode, i,
-                                     expr->X_add_number, file_name, line);
-         break;
-
-       default:
-         has_fixup = TRUE;
-         break;
+         return true;
        }
     }
-
-  xtensa_format_encode (isa, fmt, insnbuf);
-  xtensa_format_set_slot (isa, fmt, 0, insnbuf, slotbuf);
-
-  return has_fixup;
+  return false;
 }
 
 
-/* Convert the constant operands in the tinsn to slotbuf.
-   Return TRUE if there is a symbol in the immediate field.
-   (Eventually this should replace tinsn_to_insnbuf.)  */
-
-/* Before this is called,
-   1) the number of operands are correct
-   2) the tinsn is a ITYPE_INSN
-   3) ONLY the relaxable_ is built
-   4) All operands are
-       O_constant, O_symbol
-      All constants fit
+/* Encode a TInsn opcode and its constant operands into slotbuf.
+   Return TRUE if there is a symbol in the immediate field.  This
+   function assumes that:
+   1) The number of operands are correct.
+   2) The insn_type is ITYPE_INSN.
+   3) The opcode can be encoded in the specified format and slot.
+   4) Operands are either O_constant or O_symbol, and all constants fit.  */
 
-   The return value tells whether there are any remaining O_symbols.  */
-
-static bfd_boolean
+static bool
 tinsn_to_slotbuf (xtensa_format fmt,
                  int slot,
                  TInsn *tinsn,
@@ -11225,13 +12654,11 @@ tinsn_to_slotbuf (xtensa_format fmt,
 {
   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;
 
-  *((int *) &slotbuf[0]) = 0;
-  *((int *) &slotbuf[1]) = 0;
-  assert (tinsn->insn_type == ITYPE_INSN);
+  gas_assert (tinsn->insn_type == ITYPE_INSN);
   if (noperands != tinsn->ntok)
     as_fatal (_("operand number mismatch"));
 
@@ -11239,25 +12666,25 @@ tinsn_to_slotbuf (xtensa_format fmt,
     {
       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);
@@ -11268,15 +12695,15 @@ tinsn_to_slotbuf (xtensa_format fmt,
        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;
        }
     }
@@ -11285,32 +12712,124 @@ tinsn_to_slotbuf (xtensa_format fmt,
 }
 
 
+/* Encode a single TInsn into an insnbuf.  If the opcode can only be encoded
+   into a multi-slot instruction, fill the other slots with NOPs.
+   Return TRUE if there is a symbol in the immediate field.  See also the
+   assumptions listed for tinsn_to_slotbuf.  */
+
+static bool
+tinsn_to_insnbuf (TInsn *tinsn, xtensa_insnbuf insnbuf)
+{
+  static xtensa_insnbuf slotbuf = 0;
+  static vliw_insn vinsn;
+  xtensa_isa isa = xtensa_default_isa;
+  bool has_fixup = false;
+  int i;
+
+  if (!slotbuf)
+    {
+      slotbuf = xtensa_insnbuf_alloc (isa);
+      xg_init_vinsn (&vinsn);
+    }
+
+  xg_clear_vinsn (&vinsn);
+
+  bundle_tinsn (tinsn, &vinsn);
+
+  xtensa_format_encode (isa, vinsn.format, insnbuf);
+
+  for (i = 0; i < vinsn.num_slots; i++)
+    {
+      /* Only one slot may have a fix-up because the rest contains NOPs.  */
+      has_fixup |=
+       tinsn_to_slotbuf (vinsn.format, i, &vinsn.slots[i], vinsn.slotbuf[i]);
+      xtensa_format_set_slot (isa, vinsn.format, i, insnbuf, vinsn.slotbuf[i]);
+    }
+
+  return has_fixup;
+}
+
+
 /* Check the instruction arguments.  Return TRUE on failure.  */
 
-static bfd_boolean
+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;
 }
 
 
@@ -11341,7 +12860,7 @@ tinsn_from_insnbuf (TInsn *tinsn,
   /* 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++)
@@ -11364,23 +12883,12 @@ tinsn_immed_from_frag (TInsn *tinsn, fragS *fragP, int slot)
   if (fragP->tc_frag_data.slot_symbols[slot])
     {
       opnum = get_relaxable_immed (opcode);
-      assert (opnum >= 0);
-      if (fragP->tc_frag_data.slot_sub_symbols[slot])
-       {
-         set_expr_symbol_offset_diff
-           (&tinsn->tok[opnum],
-            fragP->tc_frag_data.slot_symbols[slot],
-            fragP->tc_frag_data.slot_sub_symbols[slot],
-            fragP->tc_frag_data.slot_offsets[slot]);
-       }
-      else
-       {
-         set_expr_symbol_offset
-           (&tinsn->tok[opnum],
-            fragP->tc_frag_data.slot_symbols[slot],
-            fragP->tc_frag_data.slot_offsets[slot]);
-       }
+      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];
 }
 
 
@@ -11430,10 +12938,8 @@ xg_init_vinsn (vliw_insn *v)
   if (v->insnbuf == NULL)
     as_fatal (_("out of memory"));
 
-  for (i = 0; i < MAX_SLOTS; i++)
+  for (i = 0; i < config_max_slots; i++)
     {
-      tinsn_init (&v->slots[i]);
-      v->slots[i].opcode = XTENSA_UNDEFINED;
       v->slotbuf[i] = xtensa_insnbuf_alloc (isa);
       if (v->slotbuf[i] == NULL)
        as_fatal (_("out of memory"));
@@ -11445,22 +12951,33 @@ static void
 xg_clear_vinsn (vliw_insn *v)
 {
   int i;
+
+  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++)
-    {
-      memset (&v->slots[i], 0, sizeof (TInsn));
-      v->slots[i].opcode = XTENSA_UNDEFINED;
-    }
+  for (i = 0; i < config_max_slots; i++)
+    v->slots[i].opcode = XTENSA_UNDEFINED;
+}
+
+
+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 bfd_boolean
+static bool
 vinsn_has_specific_opcodes (vliw_insn *v)
 {
   int i;
@@ -11468,9 +12985,9 @@ vinsn_has_specific_opcodes (vliw_insn *v)
   for (i = 0; i < v->num_slots; i++)
     {
       if (v->slots[i].is_specific_opcode)
-       return TRUE;
+       return true;
     }
-  return FALSE;
+  return false;
 }
 
 
@@ -11479,112 +12996,100 @@ xg_free_vinsn (vliw_insn *v)
 {
   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]);
 }
 
 
-/* Before this is called, we should have
-   filled out the following fields:
-
-   1) the number of operands for each opcode are correct
-   2) the tinsn in the slots are ITYPE_INSN
-   3) ONLY the relaxable_ is built
-   4) All operands are
-       O_constant, O_symbol
-      All constants fit
+/* Encode a vliw_insn into an insnbuf.  Return TRUE if there are any symbolic
+   operands.  See also the assumptions listed for tinsn_to_slotbuf.  */
 
-   The return value tells whether there are any remaining O_symbols.  */
-
-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]);
-      /* tinsn_has_fixup tracks if there is a fixup at all.
-        record_fixup controls globally.  I.E., we use this
-        function from several places, some of which are after
-        fixups have already been recorded.  Finally,
-        tinsn->record_fixup controls based on the individual ops,
-        which may or may not need it based on the relaxation
-        requirements.  */
-      if (tinsn_has_fixup && record_fixup)
+      if (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:
                case O_hi16:
                  if (get_relaxable_immed (opcode) == i)
                    {
-                     if (tinsn->record_fix || expr->X_op != O_symbol)
+                     /* Add a fix record for the instruction, except if this
+                        function is being called prior to relaxation, i.e.,
+                        if record_fixup is false, and the instruction might
+                        be relaxed later.  */
+                     if (record_fixup
+                         || tinsn->is_specific_opcode
+                         || !xg_is_relaxable_insn (tinsn, 0))
                        {
-                         if (!xg_add_opcode_fix
-                             (tinsn, i, fmt, slot, expr, fragP,
-                              frag_offset - fragP->fr_literal))
-                           as_bad (_("instruction with constant operands does not fit"));
+                         xg_add_opcode_fix (tinsn, i, fmt, slot, exp, fragP,
+                                            frag_offset - fragP->fr_literal);
                        }
                      else
                        {
-                         tinsn->symbol = expr->X_add_symbol;
-                         tinsn->offset = expr->X_add_number;
+                         if (exp->X_op != O_symbol)
+                           as_bad (_("invalid operand"));
+                         tinsn->symbol = exp->X_add_symbol;
+                         tinsn->offset = exp->X_add_number;
                        }
                    }
                  else
-                   as_bad (_("invalid operand %d on '%s'"),
-                           i, xtensa_opcode_name (isa, opcode));
+                   as_bad (_("symbolic operand not allowed"));
                  break;
 
                case O_constant:
                case O_register:
                  break;
 
-               case O_subtract:
-                 if (get_relaxable_immed (opcode) == i)
-                   {
-                     if (tinsn->record_fix)
-                         as_bad (_("invalid subtract operand"));
-                     else
-                       {
-                         tinsn->symbol = expr->X_add_symbol;
-                         tinsn->sub_symbol = expr->X_op_symbol;
-                         tinsn->offset = expr->X_add_number;
-                       }
-                   }
-                 else
-                   as_bad (_("invalid operand %d on '%s'"),
-                           i, xtensa_opcode_name (isa, opcode));
-                 break;
-
                default:
-                 as_bad (_("invalid expression for operand %d on '%s'"),
-                         i, xtensa_opcode_name (isa, opcode));
+                 as_bad (_("expression too complex"));
                  break;
                }
            }
@@ -11630,7 +13135,7 @@ vinsn_from_chars (vliw_insn *vinsn, char *f)
 
 /* Return TRUE if the expression is an integer constant.  */
 
-bfd_boolean
+bool
 expr_is_const (const expressionS *s)
 {
   return (s->X_op == O_constant);
@@ -11643,7 +13148,7 @@ expr_is_const (const expressionS *s)
 offsetT
 get_expr_const (const expressionS *s)
 {
-  assert (expr_is_const (s));
+  gas_assert (expr_is_const (s));
   return s->X_add_number;
 }
 
@@ -11660,7 +13165,7 @@ set_expr_const (expressionS *s, offsetT val)
 }
 
 
-bfd_boolean
+bool
 expr_is_register (const expressionS *s)
 {
   return (s->X_op == O_register);
@@ -11673,7 +13178,7 @@ expr_is_register (const expressionS *s)
 offsetT
 get_expr_register (const expressionS *s)
 {
-  assert (expr_is_register (s));
+  gas_assert (expr_is_register (s));
   return s->X_add_number;
 }
 
@@ -11690,35 +13195,20 @@ set_expr_symbol_offset (expressionS *s, symbolS *sym, offsetT offset)
 }
 
 
-/* Set the expression to symbol - minus_sym + offset.  */
-
-static void
-set_expr_symbol_offset_diff (expressionS *s,
-                            symbolS *sym,
-                            symbolS *minus_sym,
-                            offsetT offset)
-{
-  s->X_op = O_subtract;
-  s->X_add_symbol = sym;
-  s->X_op_symbol = minus_sym;  /* unused */
-  s->X_add_number = offset;
-}
-
-
 /* Return TRUE if the two expressions are equal.  */
 
-bfd_boolean
+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;
 }
 
 
@@ -11733,7 +13223,7 @@ copy_expr (expressionS *dst, const expressionS *src)
 
 struct rename_section_struct
 {
-  char *old_name;
+  const char *old_name;
   char *new_name;
   struct rename_section_struct *next;
 };
@@ -11795,8 +13285,7 @@ build_section_rename (const char *arg)
        }
 
       /* 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;
@@ -11806,7 +13295,7 @@ build_section_rename (const char *arg)
 
 
 char *
-xtensa_section_rename (char *name)
+xtensa_section_rename (const char *name)
 {
   struct rename_section_struct *r = section_rename;
 
@@ -11816,5 +13305,5 @@ xtensa_section_rename (char *name)
        return r->new_name;
     }
 
-  return name;
+  return (char *) name;
 }