2007-04-30 H.J. Lu <hongjiu.lu@intel.com>
[deliverable/binutils-gdb.git] / gas / config / tc-xtensa.c
index a2eaf96321302c4ed913b66c0602340e84885835..ffdd6c616c7ad34b12a1e9695573c8dba4376c12 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-xtensa.c -- Assemble Xtensa instructions.
-   Copyright 2003, 2004 Free Software Foundation, Inc.
+   Copyright 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
-   MA 02111-1307, USA.  */
+   the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
-#include <string.h>
 #include <limits.h>
 #include "as.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 "struc-symbol.h"
 #include "xtensa-config.h"
 
+/* Provide default values for new configuration settings.  */
+#ifndef XSHAL_ABI
+#define XSHAL_ABI 0
+#endif
+
 #ifndef uint32
 #define uint32 unsigned int
 #endif
@@ -76,12 +79,12 @@ bfd_boolean absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS;
 
 static vliw_insn cur_vinsn;
 
-size_t xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH;
+unsigned xtensa_fetch_width = XCHAL_INST_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 
+   allows us to assert that we haven't crossed over into the
    back end.  */
 static bfd_boolean past_xtensa_end = FALSE;
 
@@ -97,33 +100,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 +135,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
@@ -322,20 +320,14 @@ typedef struct op_placement_info_struct
   int num_formats;
   /* A number describing how restrictive the issue is for this
      opcode.  For example, an opcode that fits lots of different
-     formats has a high freedom, as does an opcode that fits 
+     formats has a high freedom, as does an opcode that fits
      only one format but many slots in that format.  The most
-     restrictive is the opcode that fits only one slot in one 
+     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.  */
@@ -360,6 +352,24 @@ op_placement_info_table op_placement_table;
 #define O_hi16         O_md2   /* use high 16 bits of symbolic value */
 #define O_lo16         O_md3   /* use low 16 bits of symbolic value */
 
+struct suffix_reloc_map
+{
+  char *suffix;
+  int length;
+  bfd_reloc_code_real_type reloc;
+  unsigned char 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),
+  { (char *) 0, 0,     BFD_RELOC_UNUSED,               0 }
+};
+
 
 /* Directives.  */
 
@@ -409,7 +419,7 @@ bfd_boolean directive_state[] =
   FALSE,                       /* freeregs */
   FALSE,                       /* longcalls */
   FALSE,                       /* literal_prefix */
-  TRUE,                                /* schedule */
+  FALSE,                       /* schedule */
 #if XSHAL_USE_ABSOLUTE_LITERALS
   TRUE                         /* absolute_literals */
 #else
@@ -422,8 +432,7 @@ bfd_boolean directive_state[] =
 
 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);
@@ -435,6 +444,8 @@ 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 *);
 static void xtensa_mark_literal_pool_location (void);
 static addressT get_expanded_loop_offset (xtensa_opcode);
 static fragS *get_literal_pool_location (segT);
@@ -442,11 +453,13 @@ 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 int total_frag_text_expansion (fragS *);
 
 /* Alignment Functions.  */
 
-static size_t get_text_align_power (int);
-static addressT get_text_align_max_fill_size (int, bfd_boolean, bfd_boolean);
+static int get_text_align_power (unsigned);
+static int get_text_align_max_fill_size (int, bfd_boolean, bfd_boolean);
+static int branch_align_power (segT);
 
 /* Helpers for xtensa_relax_frag().  */
 
@@ -468,12 +481,11 @@ 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);
+static segT cache_literal_section (bfd_boolean);
 
 /* Import from elf32-xtensa.c in BFD library.  */
 
-extern char *xtensa_get_property_section_name (asection *, const char *);
+extern asection *xtensa_get_property_section (asection *, const char *);
 
 /* op_placement_info functions.  */
 
@@ -481,6 +493,7 @@ static void init_op_placement_info_table (void);
 extern bfd_boolean 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.  */
 
@@ -512,8 +525,6 @@ void set_expr_const (expressionS *, offsetT);
 bfd_boolean 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 *);
 static void copy_expr (expressionS *, const expressionS *);
 
@@ -570,6 +581,7 @@ static bfd_boolean workaround_short_loop = FALSE;
 static bfd_boolean maybe_has_short_loop = FALSE;
 static bfd_boolean workaround_close_loop_end = FALSE;
 static bfd_boolean maybe_has_close_loop_end = FALSE;
+static bfd_boolean enforce_three_byte_loop_align = FALSE;
 
 /* When workaround_short_loops is TRUE, all loops with early exits must
    have at least 3 instructions.  workaround_all_short_loops is a modifier
@@ -594,6 +606,7 @@ xtensa_setup_hw_workarounds (int earliest, int latest)
       workaround_short_loop |= TRUE;
       workaround_close_loop_end |= TRUE;
       workaround_all_short_loops |= TRUE;
+      enforce_three_byte_loop_align = TRUE;
     }
 }
 
@@ -840,7 +853,7 @@ md_parse_option (int c, char *arg)
       /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section
          should be emitted or not.  FIXME: Not implemented.  */
       return 1;
-      
+
     case option_prefer_l32r:
       if (prefer_const16)
        as_fatal (_("prefer-l32r conflicts with prefer-const16"));
@@ -853,7 +866,7 @@ md_parse_option (int c, char *arg)
       prefer_const16 = 1;
       return 1;
 
-    case option_target_hardware: 
+    case option_target_hardware:
       {
        int earliest, latest = 0;
        if (*arg == 0 || *arg == '-')
@@ -946,43 +959,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);
     }
 }
 
@@ -1012,7 +998,6 @@ const pseudo_typeS md_pseudo_table[] =
   { "short", xtensa_elf_cons, 2 },
   { "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 },
@@ -1029,21 +1014,12 @@ use_transform (void)
 }
 
 
-static bfd_boolean
-use_longcalls (void)
-{
-  /* After md_end, you should be checking frag by frag, rather
-     than state directives.  */
-  assert (!past_xtensa_end);
-  return directive_state[directive_longcalls] && use_transform ();
-}
-
-
 static bfd_boolean
 do_align_targets (void)
 {
-  /* After md_end, you should be checking frag by frag, rather
-     than state directives.  */
+  /* 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);
   return align_targets && use_transform ();
 }
@@ -1149,7 +1125,7 @@ get_directive (directiveE *directive, bfd_boolean *negated)
   /* This code is a hack to make .begin [no-][generics|relax] exactly
      equivalent to .begin [no-]transform.  We should remove it when
      we stop accepting those options.  */
-     
+
   if (strncmp (input_line_pointer, "generics", strlen ("generics")) == 0)
     {
       as_warn (_("[no-]generics is deprecated; use [no-]transform instead"));
@@ -1159,7 +1135,7 @@ get_directive (directiveE *directive, bfd_boolean *negated)
     {
       as_warn (_("[no-]relax is deprecated; use [no-]transform instead"));
       directive_string = "transform";
-    }    
+    }
   else
     directive_string = input_line_pointer;
 
@@ -1187,7 +1163,6 @@ xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED)
   directiveE directive;
   bfd_boolean negated;
   emit_state *state;
-  int len;
   lit_state *ls;
 
   get_directive (&directive, &negated);
@@ -1217,7 +1192,7 @@ xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED)
       break;
 
     case directive_literal_prefix:
-      /* Have to flush pending output because a movi relaxed to an l32r 
+      /* Have to flush pending output because a movi relaxed to an l32r
         might produce a literal.  */
       md_flush_pending_output ();
       /* Check to see if the current fragment is a literal
@@ -1234,20 +1209,10 @@ xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED)
       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:
@@ -1367,11 +1332,10 @@ xtensa_end_directive (int ignore ATTRIBUTE_UNUSED)
              /* Restore the default collection sections from saved state.  */
              s = (lit_state *) state;
              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;
 
@@ -1390,28 +1354,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
@@ -1500,62 +1442,31 @@ 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;
+  char *name;
+  int len;
+
+  /* Parse the new prefix from the input_line_pointer.  */
+  SKIP_WHITESPACE ();
+  len = strspn (input_line_pointer,
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+               "abcdefghijklmnopqrstuvwxyz_/0123456789.$");
 
   /* Get a null-terminated copy of the name.  */
   name = xmalloc (len + 1);
   assert (name);
-
-  strncpy (name, start, len);
+  strncpy (name, input_line_pointer, 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");
-
-      strcat (newname, linkonce_suffix);
-      strcat (newname4, linkonce_suffix);
-    }
-  else
-    {
-      int suffix_pos = len;
-
-      /* 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;
-
-      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);
 }
 
 
@@ -1654,29 +1565,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 }
-  };
+  struct suffix_reloc_map *ptr;
 
   if (*str++ != '@')
     return BFD_RELOC_NONE;
@@ -1693,10 +1587,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]
+  for (ptr = &suffix_relocs[0]; ptr->length > 0; ptr++)
+    if (ch == ptr->suffix[0]
        && len == ptr->length
-       && memcmp (ident, ptr->string, ptr->length) == 0)
+       && memcmp (ident, ptr->suffix, ptr->length) == 0)
       {
        /* Now check for "identifier@suffix+constant".  */
        if (*str == '-' || *str == '+')
@@ -1724,6 +1618,49 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p)
 }
 
 
+/* Find the matching operator type.  */
+static unsigned char
+map_suffix_reloc_to_operator (bfd_reloc_code_real_type reloc)
+{
+  struct suffix_reloc_map *sfx;
+  unsigned char operator = (unsigned char) -1;
+  
+  for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++)
+    {
+      if (sfx->reloc == reloc)
+       {
+         operator = sfx->operator;
+         break;
+       }
+    }
+  assert (operator != (unsigned char) -1);
+  return operator;
+}
+
+
+/* Find the matching reloc type.  */
+static bfd_reloc_code_real_type
+map_operator_to_reloc (unsigned char operator)
+{
+  struct suffix_reloc_map *sfx;
+  bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
+
+  for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++)
+    {
+      if (sfx->operator == operator)
+       {
+         reloc = sfx->reloc;
+         break;
+       }
+    }
+
+  if (reloc == BFD_RELOC_UNUSED)
+    return BFD_RELOC_32;
+
+  return reloc;
+}
+
+
 static const char *
 expression_end (const char *name)
 {
@@ -1824,34 +1761,32 @@ expression_maybe_register (xtensa_opcode opc, int opnd, expressionS *tok)
        }
 
       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)
+         if (reloc == BFD_RELOC_UNUSED)
            {
-             default:
-             case BFD_RELOC_UNUSED:
-               as_bad (_("unsupported relocation"));
-               break;
-
-             case BFD_RELOC_XTENSA_PLT:
-               tok->X_op = O_pltrel;
-               break;
+             as_bad (_("unsupported relocation"));
+             return;
+           }
 
-             case BFD_RELOC_LO16:
-               if (tok->X_op == O_constant)
+         if (tok->X_op == O_constant)
+           {
+             switch (reloc)
+               {
+               case BFD_RELOC_LO16:
                  tok->X_add_number &= 0xffff;
-               else
-                 tok->X_op = O_lo16;
-               break;
+                 return;
 
-             case BFD_RELOC_HI16:
-               if (tok->X_op == O_constant)
+               case BFD_RELOC_HI16:
                  tok->X_add_number = ((unsigned) tok->X_add_number) >> 16;
-               else
-                 tok->X_op = O_hi16;
-               break;
+                 return;
+
+               default:
+                 break;
+               }
            }
+         tok->X_op = map_suffix_reloc_to_operator (reloc);
        }
     }
   else
@@ -1932,9 +1867,9 @@ tokenize_arguments (char **args, char *str)
 
          input_line_pointer = arg_end;
          num_args += 1;
-         saw_comma = FALSE; 
+         saw_comma = FALSE;
          saw_colon = FALSE;
-         saw_arg = TRUE; 
+         saw_arg = TRUE;
          break;
        }
     }
@@ -1951,7 +1886,7 @@ err:
   else if (saw_colon)
     as_bad (_("extra colon"));
   else if (!saw_arg)
-    as_bad (_("missing argument"));  
+    as_bad (_("missing argument"));
   else
     as_bad (_("missing comma or colon"));
   input_line_pointer = old_input_line_pointer;
@@ -2051,7 +1986,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;
@@ -2217,14 +2152,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');
 
@@ -2254,7 +2185,7 @@ xg_translate_sysreg_op (char **popname, int *pnum_args, char **arg_strings)
       if (sr == XTENSA_UNDEFINED)
        {
          as_bad (_("invalid register number (%ld) for '%s' instruction"),
-                 val, opname);
+                 (long) val, opname);
          return -1;
        }
     }
@@ -2270,8 +2201,7 @@ xg_translate_sysreg_op (char **popname, int *pnum_args, char **arg_strings)
   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);
+  sprintf (new_opname, "%s.%s", *popname, sr_name);
   free (*popname);
   *popname = new_opname;
 
@@ -2323,7 +2253,7 @@ xtensa_translate_old_userreg_ops (char **popname)
       if (sr == XTENSA_UNDEFINED)
        {
          as_bad (_("invalid register number (%ld) for '%s'"),
-                 val, opname);
+                 (long) val, opname);
          return -1;
        }
     }
@@ -2380,9 +2310,6 @@ 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;
-
   if (*opname == '_')
     {
       has_underbar = TRUE;
@@ -2425,7 +2352,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)
@@ -2532,7 +2463,7 @@ get_opcode_from_buf (const char *buf, int slot)
       slotbuf = xtensa_insnbuf_alloc (isa);
     }
 
-  xtensa_insnbuf_from_chars (isa, insnbuf, buf, 0);
+  xtensa_insnbuf_from_chars (isa, insnbuf, (const unsigned char *) buf, 0);
   fmt = xtensa_format_decode (isa, insnbuf);
   if (fmt == XTENSA_UNDEFINED)
     return XTENSA_UNDEFINED;
@@ -2629,7 +2560,7 @@ 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)
+  if (xtensa_opcode_is_call (isa, opcode) != 1)
     return FALSE;
 
   num_operands = xtensa_opcode_num_operands (isa, opcode);
@@ -2712,12 +2643,16 @@ 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 %u is out of range for '%s'"), value,
-                     xtensa_opcode_name (xtensa_default_isa, opcode));
+                     _("operand %d of '%s' has out of range value '%u'"), 
+                     operand + 1,
+                     xtensa_opcode_name (xtensa_default_isa, opcode),
+                     value);
       else
        as_bad_where ((char *) file, line,
-                     _("operand %u is invalid for '%s'"), value,
-                     xtensa_opcode_name (xtensa_default_isa, opcode));
+                     _("operand %d of '%s' has invalid value '%u'"),
+                     operand + 1,
+                     xtensa_opcode_name (xtensa_default_isa, opcode),
+                     value);
       return;
     }
 
@@ -2991,52 +2926,23 @@ is_unique_insn_expansion (TransitionRule *r)
 }
 
 
-static int
-xg_get_build_instr_size (BuildInstr *insn)
-{
-  assert (insn->typ == INSTR_INSTR);
-  return xg_get_single_size (insn->opcode);
-}
-
+/* Check if there is exactly one relaxation for INSN that converts it to
+   another instruction of equal or larger size.  If so, and if TARG is
+   non-null, go ahead and generate the relaxed instruction into TARG.  If
+   NARROW_ONLY is true, then only consider relaxations that widen a narrow
+   instruction, i.e., ignore relaxations that convert to an instruction of
+   equal size.  In some contexts where this function is used, only
+   a single widening is allowed and the NARROW_ONLY argument is used to
+   exclude cases like ADDI being "widened" to an ADDMI, which may
+   later be relaxed to an ADDMI/ADDI pair.  */
 
-static bfd_boolean
-xg_is_narrow_insn (TInsn *insn)
+bfd_boolean
+xg_is_single_relaxable_insn (TInsn *insn, TInsn *targ, bfd_boolean narrow_only)
 {
   TransitionTable *table = xg_build_widen_table (&transition_rule_cmp);
   TransitionList *l;
-  int num_match = 0;
-  assert (insn->insn_type == ITYPE_INSN);
-  assert (insn->opcode < table->num_opcodes);
-
-  for (l = table->table[insn->opcode]; l != NULL; l = l->next)
-    {
-      TransitionRule *rule = l->rule;
-
-      if (xg_instruction_matches_rule (insn, rule)
-         && is_unique_insn_expansion (rule))
-       {
-         /* It only generates one instruction... */
-         assert (insn->insn_type == ITYPE_INSN);
-         /* ...and it is a larger instruction.  */
-         if (xg_get_single_size (insn->opcode)
-             < xg_get_build_instr_size (rule->to_instr))
-           {
-             num_match++;
-             if (num_match > 1)
-               return FALSE;
-           }
-       }
-    }
-  return (num_match == 1);
-}
+  TransitionRule *match = 0;
 
-
-static bfd_boolean
-xg_is_single_relaxable_insn (TInsn *insn)
-{
-  TransitionTable *table = xg_build_widen_table (&transition_rule_cmp);
-  TransitionList *l;
-  int num_match = 0;
   assert (insn->insn_type == ITYPE_INSN);
   assert (insn->opcode < table->num_opcodes);
 
@@ -3045,21 +2951,21 @@ xg_is_single_relaxable_insn (TInsn *insn)
       TransitionRule *rule = l->rule;
 
       if (xg_instruction_matches_rule (insn, rule)
-         && is_unique_insn_expansion (rule))
+         && is_unique_insn_expansion (rule)
+         && (xg_get_single_size (insn->opcode) + (narrow_only ? 1 : 0)
+             <= xg_get_single_size (rule->to_instr->opcode)))
        {
-         /* It only generates one instruction... */
-         assert (insn->insn_type == ITYPE_INSN);
-         /* ... and it is a larger instruction.  */
-         if (xg_get_single_size (insn->opcode)
-             <= xg_get_build_instr_size (rule->to_instr))
-           {
-             num_match++;
-             if (num_match > 1)
-               return FALSE;
-           }
+         if (match)
+           return FALSE;
+         match = rule;
        }
     }
-  return (num_match == 1);
+  if (!match)
+    return FALSE;
+
+  if (targ)
+    xg_build_to_insn (targ, insn, match->to_instr);
+  return TRUE;
 }
 
 
@@ -3311,22 +3217,28 @@ xg_symbolic_immeds_fit (const TInsn *insn,
          break;
 
        case O_symbol:
-         /* We only allow symbols for pc-relative stuff.
+         /* We only allow symbols for PC-relative references.
             If pc_frag == 0, then we don't have frag locations yet.  */
-         if (pc_frag == 0)
+         if (pc_frag == 0
+             || xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 0)
            return FALSE;
 
-         /* If it is PC-relative and the symbol is not in the same 
-            segment as the PC.... */
-         if (xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 0
-             || S_GET_SEGMENT (expr->X_add_symbol) != pc_seg)
+         /* If it is a weak symbol, then assume it won't reach.  */
+         if (S_IS_WEAK (expr->X_add_symbol))
            return FALSE;
 
-         /* If it is a weak symbol, then assume it won't reach.  This will
-            only affect calls when longcalls are enabled, because if
-            longcalls are disabled, then the call is marked as a specific
-            opcode.  */
-         if (S_IS_WEAK (expr->X_add_symbol))
+         if (is_direct_call_opcode (insn->opcode)
+             && ! pc_frag->tc_frag_data.use_longcalls)
+           {
+             /* 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;
+           }
+
+         /* 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;
@@ -3346,7 +3258,7 @@ xg_symbolic_immeds_fit (const TInsn *insn,
            {
              target += stretch;
            }
+
          new_offset = target;
          xtensa_operand_do_reloc (isa, insn->opcode, i, &new_offset, pc);
          if (xg_check_operand (new_offset, insn->opcode, i))
@@ -3371,8 +3283,8 @@ 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->linenum = insn->linenum;
   switch (bi->typ)
     {
     case INSTR_INSTR:
@@ -3581,34 +3493,6 @@ xg_expand_to_stack (IStack *istack, TInsn *insn, int lateral_steps)
   return FALSE;
 }
 
-
-static bfd_boolean
-xg_expand_narrow (TInsn *targ, TInsn *insn)
-{
-  TransitionTable *table = xg_build_widen_table (&transition_rule_cmp);
-  TransitionList *l;
-
-  assert (insn->insn_type == ITYPE_INSN);
-  assert (insn->opcode < table->num_opcodes);
-
-  for (l = table->table[insn->opcode]; l != NULL; l = l->next)
-    {
-      TransitionRule *rule = l->rule;
-      if (xg_instruction_matches_rule (insn, rule)
-         && is_unique_insn_expansion (rule))
-       {
-         /* Is it a larger instruction?  */
-         if (xg_get_single_size (insn->opcode)
-             <= xg_get_build_instr_size (rule->to_instr))
-           {
-             xg_build_to_insn (targ, insn, rule->to_instr);
-             return FALSE;
-           }
-       }
-    }
-  return TRUE;
-}
-
 \f
 /* Relax the assembly instruction at least "min_steps".
    Return the number of steps taken.  */
@@ -3644,17 +3528,13 @@ xg_assembly_relax (IStack *istack,
     }
   current_insn = *insn;
 
-  /* Walk through all of the single instruction expansions. */
-  while (xg_is_single_relaxable_insn (&current_insn))
+  /* Walk through all of the single instruction expansions.  */
+  while (xg_is_single_relaxable_insn (&current_insn, &single_target, FALSE))
     {
-      int error_val = xg_expand_narrow (&single_target, &current_insn);
-
-      assert (!error_val);
-
+      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);
@@ -3771,8 +3651,8 @@ 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)
+  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++)
@@ -3803,7 +3683,7 @@ is_branch_jmp_to_next (TInsn *insn, fragS *fragP)
   if (target_frag == NULL)
     return FALSE;
 
-  if (is_next_frag_target (fragP->fr_next, target_frag) 
+  if (is_next_frag_target (fragP->fr_next, target_frag)
       && S_GET_VALUE (sym) == target_frag->fr_address)
     return TRUE;
 
@@ -3860,13 +3740,13 @@ xg_build_token_insn (BuildInstr *instr_spec, TInsn *old_insn, TInsn *new_insn)
       new_insn->insn_type = ITYPE_INSN;
       new_insn->opcode = instr_spec->opcode;
       new_insn->is_specific_opcode = FALSE;
-      new_insn->loc = old_insn->loc;
+      new_insn->linenum = old_insn->linenum;
       break;
     case INSTR_LITERAL_DEF:
       new_insn->insn_type = ITYPE_LITERAL;
       new_insn->opcode = XTENSA_UNDEFINED;
       new_insn->is_specific_opcode = FALSE;
-      new_insn->loc = old_insn->loc;
+      new_insn->linenum = old_insn->linenum;
       break;
     case INSTR_LABEL_DEF:
       as_bad (_("INSTR_LABEL_DEF not supported yet"));
@@ -3942,16 +3822,17 @@ xg_simplify_insn (TInsn *old_insn, TInsn *new_insn)
 
 /* xg_expand_assembly_insn: (1) Simplify the instruction, i.e., l32i ->
    l32i.n. (2) Check the number of operands.  (3) Place the instruction
-   tokens into the stack or if we can relax it at assembly time, place
-   multiple instructions/literals onto the stack.  Return FALSE if no
-   error.  */
+   tokens into the stack or relax it and place multiple
+   instructions/literals onto the stack.  Return FALSE if no error.  */
 
 static bfd_boolean
 xg_expand_assembly_insn (IStack *istack, TInsn *orig_insn)
 {
   int noperands;
   TInsn new_insn;
-  memset (&new_insn, 0, sizeof (TInsn));
+  bfd_boolean do_expand;
+
+  tinsn_init (&new_insn);
 
   /* Narrow it if we can.  xg_simplify_insn now does all the
      appropriate checking (e.g., for the density option).  */
@@ -3976,57 +3857,46 @@ xg_expand_assembly_insn (IStack *istack, TInsn *orig_insn)
 
   /* If there are not enough operands, we will assert above.  If there
      are too many, just cut out the extras here.  */
-
   orig_insn->ntok = noperands;
 
-  /* Cases:
-
-     Instructions with all constant immeds:
-     Assemble them and relax the instruction if possible.
-     Give error if not possible; no fixup needed.
-
-     Instructions with symbolic immeds:
-     Assemble them with a Fix up (that may cause instruction expansion).
-     Also close out the fragment if the fixup may cause instruction expansion.
-
-     There are some other special cases where we need alignment.
-     1) before certain instructions with required alignment (OPCODE_ALIGN)
-     2) before labels that have jumps (LABEL_ALIGN)
-     3) after call instructions (RETURN_ALIGN)
-        Multiple of these may be possible on the same fragment.
-       If so, make sure to satisfy the required alignment.
-       Then try to get the desired alignment.  */
-
   if (tinsn_has_invalid_symbolic_operands (orig_insn))
     return TRUE;
 
-  if (orig_insn->is_specific_opcode || !use_transform ())
-    {
-      istack_push (istack, orig_insn);
-      return FALSE;
-    }
+  /* If the instruction will definitely need to be relaxed, it is better
+     to expand it now for better scheduling.  Decide whether to expand
+     now....  */
+  do_expand = (!orig_insn->is_specific_opcode && use_transform ());
+
+  /* Calls should be expanded to longcalls only in the backend relaxation
+     so that the assembly scheduler will keep the L32R/CALLX instructions
+     adjacent.  */
+  if (is_direct_call_opcode (orig_insn->opcode))
+    do_expand = FALSE;
 
   if (tinsn_has_symbolic_operands (orig_insn))
     {
-      if (tinsn_has_complex_operands (orig_insn))
-       xg_assembly_relax (istack, orig_insn, 0, 0, 0, 0, 0);
-      else
-       istack_push (istack, orig_insn);
+      /* The values of symbolic operands are not known yet, so only expand
+        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;
     }
+  else if (xg_immeds_fit (orig_insn))
+    do_expand = FALSE;
+
+  if (do_expand)
+    xg_assembly_relax (istack, orig_insn, 0, 0, 0, 0, 0);
   else
-    {
-      if (xg_immeds_fit (orig_insn))
-       istack_push (istack, orig_insn);
-      else
-       xg_assembly_relax (istack, orig_insn, 0, 0, 0, 0, 0);
-    }
+    istack_push (istack, orig_insn);
 
   return FALSE;
 }
 
 
 /* Return TRUE if the section flags are marked linkonce
-   or the name is .gnu.linkonce*.  */
+   or the name is .gnu.linkonce.*.  */
+
+static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
 
 static bfd_boolean
 get_is_linkonce_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec)
@@ -4037,13 +3907,10 @@ get_is_linkonce_section (bfd *abfd ATTRIBUTE_UNUSED, segT 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);
 }
 
@@ -4083,7 +3950,6 @@ xtensa_create_literal_symbol (segT sec, fragS *frag)
 
   xtensa_add_literal_sym (symbolP);
 
-  frag->tc_frag_data.is_literal = TRUE;
   lit_num++;
   return symbolP;
 }
@@ -4096,6 +3962,8 @@ xg_assemble_literal (/* const */ TInsn *insn)
 {
   emit_state state;
   symbolS *lit_sym = NULL;
+  bfd_reloc_code_real_type reloc;
+  char *p;
 
   /* size = 4 for L32R.  It could easily be larger when we move to
      larger constants.  Add a parameter later.  */
@@ -4118,7 +3986,7 @@ xg_assemble_literal (/* const */ TInsn *insn)
       if (size > litsize)
        {
          /* This happens when someone writes a "movi a2, big_number".  */
-         as_bad_where (frag_now->fr_file, frag_now->fr_line, 
+         as_bad_where (frag_now->fr_file, frag_now->fr_line,
                        _("invalid immediate"));
          xtensa_restore_emit_state (&state);
          return NULL;
@@ -4131,25 +3999,29 @@ 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_pltrel:
+      p = frag_more (litsize);
       xtensa_set_frag_assembly_state (frag_now);
+      reloc = map_operator_to_reloc (emit_val->X_op);
       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, 0, reloc);
+      break;
+
+    default:
+      emit_expr (emit_val, litsize);
+      break;
     }
-  else
-    emit_expr (emit_val, litsize);
 
   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);
@@ -4178,7 +4050,6 @@ xg_assemble_literal_space (/* const */ int size, int slot)
 
   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);
 
@@ -4231,7 +4102,7 @@ xg_add_opcode_fix (TInsn *tinsn,
   if (opnum != get_relaxable_immed (opcode))
     {
       as_bad (_("invalid relocation for operand %i of '%s'"),
-             opnum, xtensa_opcode_name (xtensa_default_isa, opcode));
+             opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
       return FALSE;
     }
 
@@ -4241,7 +4112,7 @@ xg_add_opcode_fix (TInsn *tinsn,
   if (expr->X_op == O_lo16 || expr->X_op == O_hi16)
     {
       as_bad (_("invalid expression for operand %i of '%s'"),
-             opnum, xtensa_opcode_name (xtensa_default_isa, opcode));
+             opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
       return FALSE;
     }
 
@@ -4265,23 +4136,17 @@ xg_add_opcode_fix (TInsn *tinsn,
   fmt_length = xtensa_format_length (xtensa_default_isa, fmt);
   the_fix = fix_new_exp (fragP, offset, fmt_length, expr,
                         howto->pc_relative, reloc);
-
-  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->fx_no_overflow = 1;
   the_fix->tc_fix_data.X_add_symbol = expr->X_add_symbol;
   the_fix->tc_fix_data.X_add_number = expr->X_add_number;
   the_fix->tc_fix_data.slot = slot;
-  
+
   return TRUE;
 }
 
 
 static bfd_boolean
 xg_emit_insn_to_buf (TInsn *tinsn,
-                    xtensa_format fmt,
                     char *buf,
                     fragS *fragP,
                     offsetT offset,
@@ -4290,6 +4155,7 @@ xg_emit_insn_to_buf (TInsn *tinsn,
   static xtensa_insnbuf insnbuf = NULL;
   bfd_boolean has_symbolic_immed = FALSE;
   bfd_boolean ok = TRUE;
+
   if (!insnbuf)
     insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
 
@@ -4297,14 +4163,17 @@ 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))
+      if (!xg_add_opcode_fix (tinsn, opnum, fmt, slot, exp, fragP, offset))
        ok = FALSE;
     }
   fragP->tc_frag_data.is_insn = TRUE;
-  xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf, buf, 0);
+  xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf,
+                          (unsigned char *) buf, 0);
   return ok;
 }
 
@@ -4329,7 +4198,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;
@@ -4394,7 +4262,7 @@ is_bad_loopend_opcode (const TInsn *tinsn)
       || opcode == xtensa_waiti_opcode
       || opcode == xtensa_rsr_lcount_opcode)
     return TRUE;
-  
+
   return FALSE;
 }
 
@@ -4436,7 +4304,7 @@ next_non_empty_frag (const fragS *fragP)
 {
   fragS *next_fragP = fragP->fr_next;
 
-  /* Sometimes an empty will end up here due storage allocation issues. 
+  /* Sometimes an empty will end up here due storage allocation issues.
      So we have to skip until we find something legit.  */
   while (next_fragP && next_fragP->fr_fix == 0)
     next_fragP = next_fragP->fr_next;
@@ -4473,7 +4341,7 @@ frag_format_size (const fragS *fragP)
   static xtensa_insnbuf insnbuf = NULL;
   xtensa_isa isa = xtensa_default_isa;
   xtensa_format fmt;
-  int fmt_size; 
+  int fmt_size;
 
   if (!insnbuf)
     insnbuf = xtensa_insnbuf_alloc (isa);
@@ -4481,7 +4349,8 @@ frag_format_size (const fragS *fragP)
   if (fragP == NULL)
     return XTENSA_UNDEFINED;
 
-  xtensa_insnbuf_from_chars (isa, insnbuf, fragP->fr_literal, 0);
+  xtensa_insnbuf_from_chars (isa, insnbuf,
+                            (unsigned char *) fragP->fr_literal, 0);
 
   fmt = xtensa_format_decode (isa, insnbuf);
   if (fmt == XTENSA_UNDEFINED)
@@ -4493,7 +4362,7 @@ frag_format_size (const fragS *fragP)
   if (fragP->fr_opcode != fragP->fr_literal)
     return fmt_size;
 
-  /* If during relaxation we have to pull an instruction out of a 
+  /* If during relaxation we have to pull an instruction out of a
      multi-slot instruction, we will return the more conservative
      number.  This works because alignment on bigger instructions
      is more restrictive than alignment on smaller instructions.
@@ -4514,7 +4383,7 @@ frag_format_size (const fragS *fragP)
   if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP1
       || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP2)
     return 3;
-  
+
   if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
     return 2 + fragP->tc_frag_data.text_expansion[0];
 
@@ -4530,16 +4399,36 @@ 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.  */
 
 static void
-update_next_frag_state (fragS *fragP, bfd_boolean unreachable)
+update_next_frag_state (fragS *fragP)
 {
   fragS *next_fragP = fragP->fr_next;
   fragS *new_target = NULL;
 
-  if (align_targets) 
+  if (align_targets)
     {
       /* We are guaranteed there will be one of these...   */
       while (!(next_fragP->fr_type == rs_machine_dependent
@@ -4562,36 +4451,17 @@ update_next_frag_state (fragS *fragP, bfd_boolean unreachable)
              && (new_target->fr_subtype == RELAX_MAYBE_DESIRE_ALIGN
                  || new_target->fr_subtype == RELAX_DESIRE_ALIGN));
     }
-  if (unreachable)
-    {
-      if (align_targets)
-       {
-         next_fragP->fr_subtype = RELAX_UNREACHABLE;
-         next_fragP->tc_frag_data.is_unreachable = TRUE;
-         new_target->fr_subtype = RELAX_DESIRE_ALIGN;
-         new_target->tc_frag_data.is_branch_target = TRUE;
-       }
-      while (next_fragP && next_fragP->fr_fix == 0)
-       {
-         if (next_fragP->fr_type == rs_machine_dependent
-             && next_fragP->fr_subtype == RELAX_LOOP_END)
-           {
-             next_fragP->fr_subtype = RELAX_LOOP_END_ADD_NOP;
-             return;
-           }
 
-         next_fragP = next_fragP->fr_next;
-       }
-    }
-  else
+  while (next_fragP && next_fragP->fr_fix == 0)
     {
-      if (align_targets)
+      if (next_fragP->fr_type == rs_machine_dependent
+         && next_fragP->fr_subtype == RELAX_LOOP_END)
        {
-         next_fragP->fr_subtype = RELAX_MAYBE_UNREACHABLE;
-         next_fragP->tc_frag_data.is_unreachable = FALSE;
-         new_target->fr_subtype = RELAX_MAYBE_DESIRE_ALIGN;
-         new_target->tc_frag_data.is_branch_target = FALSE;
+         next_fragP->fr_subtype = RELAX_LOOP_END_ADD_NOP;
+         return;
        }
+
+      next_fragP = next_fragP->fr_next;
     }
 }
 
@@ -4615,7 +4485,7 @@ next_frag_is_branch_target (const fragS *fragP)
 static bfd_boolean
 next_frag_is_loop_target (const fragS *fragP)
 {
-  /* Sometimes an empty will end up here due storage allocation issues. 
+  /* Sometimes an empty will end up here due storage allocation issues.
      So we have to skip until we find something legit. */
   for (fragP = fragP->fr_next; fragP; fragP = fragP->fr_next)
     {
@@ -4668,21 +4538,18 @@ xtensa_mark_literal_pool_location (void)
   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 the fr_var of these frags
-     so we can later move the literal's fixes into this
-     frchain's fix list.  We can use fr_var because fr_var's
-     interpretation depends solely on the fr_type and subtype.  */
+  /* 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_variant (rs_machine_dependent, 0, (int) frchain_now,
+  frag_now->tc_frag_data.lit_frchain = frchain_now;
+  frag_variant (rs_machine_dependent, 0, 0,
                RELAX_LITERAL_POOL_BEGIN, NULL, 0, NULL);
   xtensa_set_frag_assembly_state (frag_now);
-  frag_variant (rs_machine_dependent, 0, (int) now_seg,
+  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);
 
@@ -4738,7 +4605,7 @@ build_nop (TInsn *tinsn, int size)
    allocated "buf" with at least "size" bytes.  */
 
 static void
-assemble_nop (size_t size, char *buf)
+assemble_nop (int size, char *buf)
 {
   static xtensa_insnbuf insnbuf = NULL;
   TInsn tinsn;
@@ -4749,7 +4616,8 @@ assemble_nop (size_t size, char *buf)
     insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
 
   tinsn_to_insnbuf (&tinsn, insnbuf);
-  xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf, buf, 0);
+  xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf,
+                          (unsigned char *) buf, 0);
 }
 
 
@@ -4802,10 +4670,12 @@ xtensa_set_frag_assembly_state (fragS *fragP)
     fragP->tc_frag_data.is_no_density = TRUE;
 
   /* This function is called from subsegs_finish, which is called
-     after xtensa_end, so we can't use "use_transform" or 
+     after xtensa_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;
+  if (directive_state[directive_longcalls])
+    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;
@@ -4864,6 +4734,8 @@ xtensa_find_unmarked_state_frags (void)
                        last_fragP->tc_frag_data.is_no_density;
                      fragP->tc_frag_data.is_no_transform =
                        last_fragP->tc_frag_data.is_no_transform;
+                     fragP->tc_frag_data.use_longcalls =
+                       last_fragP->tc_frag_data.use_longcalls;
                      fragP->tc_frag_data.use_absolute_literals =
                        last_fragP->tc_frag_data.use_absolute_literals;
                    }
@@ -4884,9 +4756,9 @@ xtensa_find_unaligned_branch_targets (bfd *abfd ATTRIBUTE_UNUSED,
   flagword flags = bfd_get_section_flags (abfd, sec);
   segment_info_type *seginfo = seg_info (sec);
   fragS *frag = seginfo->frchainP->frch_root;
-  
+
   if (flags & SEC_CODE)
-    {  
+    {
       xtensa_isa isa = xtensa_default_isa;
       xtensa_insnbuf insnbuf = xtensa_insnbuf_alloc (isa);
       while (frag != NULL)
@@ -4894,17 +4766,19 @@ xtensa_find_unaligned_branch_targets (bfd *abfd ATTRIBUTE_UNUSED,
          if (frag->tc_frag_data.is_branch_target)
            {
              int op_size;
-             int frag_addr;
+             addressT branch_align, frag_addr;
              xtensa_format fmt;
 
-             xtensa_insnbuf_from_chars (isa, insnbuf, frag->fr_literal, 0);
+             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 > (int) xtensa_fetch_width)
+             branch_align = 1 << branch_align_power (sec);
+             frag_addr = frag->fr_address % branch_align;
+             if (frag_addr + op_size > branch_align)
                as_warn_where (frag->fr_file, frag->fr_line,
                               _("unaligned branch target: %d bytes at 0x%lx"),
-                              op_size, frag->fr_address);
+                              op_size, (long) frag->fr_address);
            }
          frag = frag->fr_next;
        }
@@ -4922,27 +4796,28 @@ xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED,
   segment_info_type *seginfo = seg_info (sec);
   fragS *frag = seginfo->frchainP->frch_root;
   xtensa_isa isa = xtensa_default_isa;
-  
+
   if (flags & SEC_CODE)
-    {  
+    {
       xtensa_insnbuf insnbuf = xtensa_insnbuf_alloc (isa);
       while (frag != NULL)
        {
          if (frag->tc_frag_data.is_first_loop_insn)
            {
              int op_size;
-             int frag_addr;
+             addressT frag_addr;
              xtensa_format fmt;
 
-             xtensa_insnbuf_from_chars (isa, insnbuf, frag->fr_literal, 0);
+             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 > (signed) 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, frag->fr_address);
+                              op_size, (long) frag->fr_address);
            }
          frag = frag->fr_next;
        }
@@ -4951,8 +4826,8 @@ xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED,
 }
 
 
-static void
-xg_apply_tentative_value (fixS *fixP, valueT val)
+static int
+xg_apply_fix_value (fixS *fixP, valueT val)
 {
   xtensa_isa isa = xtensa_default_isa;
   static xtensa_insnbuf insnbuf = NULL;
@@ -4973,7 +4848,7 @@ xg_apply_tentative_value (fixS *fixP, valueT val)
       slotbuf = xtensa_insnbuf_alloc (isa);
     }
 
-  xtensa_insnbuf_from_chars (isa, insnbuf, fixpos, 0);
+  xtensa_insnbuf_from_chars (isa, insnbuf, (unsigned char *) fixpos, 0);
   fmt = xtensa_format_decode (isa, insnbuf);
   if (fmt == XTENSA_UNDEFINED)
     as_fatal (_("undecodable fix"));
@@ -4984,18 +4859,18 @@ xg_apply_tentative_value (fixS *fixP, valueT val)
 
   /* CONST16 immediates are not PC-relative, despite the fact that we
      reuse the normal PC-relative operand relocations for the low part
-     of a CONST16 operand.  The code in tc_gen_reloc does not decode
-     the opcodes so it is more convenient to detect this special case
-     here.  */
+     of a CONST16 operand.  */
   if (opcode == xtensa_const16_opcode)
-    return;
+    return 0;
 
   xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode,
                              get_relaxable_immed (opcode), val,
                              fixP->fx_file, fixP->fx_line);
 
   xtensa_format_set_slot (isa, fmt, slot, insnbuf, slotbuf);
-  xtensa_insnbuf_to_chars (isa, insnbuf, fixpos, 0);
+  xtensa_insnbuf_to_chars (isa, insnbuf, (unsigned char *) fixpos, 0);
+
+  return 1;
 }
 
 \f
@@ -5041,12 +4916,8 @@ md_begin (void)
 
   linkrelax = 1;
 
-  /* 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);
 
@@ -5106,6 +4977,16 @@ xtensa_init_fix_data (fixS *x)
 void
 xtensa_frob_label (symbolS *sym)
 {
+  float freq;
+
+  if (cur_vinsn.inside_bundle)
+    {
+      as_bad (_("labels are not valid inside bundles"));
+      return;
+    }
+
+  freq = get_subseg_target_freq (now_seg, now_subseg);
+
   /* Since the label was already attached to a frag associated with the
      previous basic block, it now needs to be reset to the current frag.  */
   symbol_set_frag (sym, frag_now);
@@ -5116,10 +4997,19 @@ xtensa_frob_label (symbolS *sym)
   else
     xtensa_add_insn_label (sym);
 
-  if (symbol_get_tc (sym)->is_loop_target
-      && (get_last_insn_flags (now_seg, now_subseg)
+  if (symbol_get_tc (sym)->is_loop_target)
+    {
+      if ((get_last_insn_flags (now_seg, now_subseg)
          & FLAG_IS_BAD_LOOPEND) != 0)
-    as_bad (_("invalid last instruction for a zero-overhead loop"));
+       as_bad (_("invalid last instruction for a zero-overhead loop"));
+
+      xtensa_set_frag_assembly_state (frag_now);
+      frag_var (rs_machine_dependent, 4, 4, RELAX_LOOP_END,
+               frag_now->fr_symbol, frag_now->fr_offset, NULL);
+
+      xtensa_set_frag_assembly_state (frag_now);
+      xtensa_move_labels (frag_now, 0);
+    }
 
   /* No target aligning in the absolute section.  */
   if (now_seg != absolute_section
@@ -5127,30 +5017,14 @@ xtensa_frob_label (symbolS *sym)
       && !is_unaligned_label (sym)
       && !generating_literals)
     {
-      float freq = get_subseg_target_freq (now_seg, now_subseg);
       xtensa_set_frag_assembly_state (frag_now);
 
-      /* The only time this type of frag grows is when there is a
-        negatable branch that needs to be relaxed as the last
-        instruction in a zero-overhead loop.  Because alignment frags
-        are so common, marking them all as possibly growing four
-        bytes makes any worst-case analysis appear much worse than it
-        is.  So, we make fr_var not actually reflect the amount of
-        memory allocated at the end of this frag, but rather the
-        amount of memory this frag might grow.  The "4, 0" below
-        allocates four bytes at the end of the frag for room to grow
-        if we need to relax a loop end with a NOP.  Frags prior to
-        this one might grow to align this one, but the frag itself
-        won't grow unless it meets the condition above.  */
-
-#define RELAX_LOOP_END_BYTES 4
-
       frag_var (rs_machine_dependent,
-               RELAX_LOOP_END_BYTES, (int) freq,
+               0, (int) freq,
                RELAX_DESIRE_ALIGN_IF_TARGET,
                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.  */
@@ -5164,6 +5038,8 @@ xtensa_frob_label (symbolS *sym)
   /* 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;
+
+  dwarf2_emit_label (sym);
 }
 
 
@@ -5217,6 +5093,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"));
 
@@ -5256,7 +5141,7 @@ void
 md_assemble (char *str)
 {
   xtensa_isa isa = xtensa_default_isa;
-  char *opname;
+  char *opname, *file_name;
   unsigned opnamelen;
   bfd_boolean has_underbar = FALSE;
   char *arg_strings[MAX_INSN_ARGS];
@@ -5317,11 +5202,6 @@ md_assemble (char *str)
       return;
     }
 
-  /* Special case: The call instructions should be marked "specific opcode"
-     to keep them from expanding.  */
-  if (!use_longcalls () && is_direct_call_opcode (orig_insn.opcode))
-    orig_insn.is_specific_opcode = TRUE;
-
   /* Parse the arguments.  */
   if (parse_arguments (&orig_insn, num_args, arg_strings))
     {
@@ -5350,28 +5230,20 @@ md_assemble (char *str)
       return;
     }
 
-  dwarf2_where (&orig_insn.loc);
-  
+  /* A FLIX bundle may be spread across multiple input lines.  We want to
+     report the first such line in the debug information.  Record the line
+     number for each TInsn (assume the file name doesn't change), so the
+     first line can be found later.  */
+  as_where (&file_name, &orig_insn.linenum);
+
   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:
@@ -5423,7 +5295,7 @@ xtensa_handle_align (fragS *fragP)
       int count;
       count = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
       if (count != 0)
-       as_bad_where (fragP->fr_file, fragP->fr_line, 
+       as_bad_where (fragP->fr_file, fragP->fr_line,
                      _("unaligned entry instruction"));
     }
 }
@@ -5469,11 +5341,8 @@ md_pcrel_from (fixS *fixP)
   valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
   bfd_boolean alt_reloc;
 
-  if (fixP->fx_done)
-    return addr;
-
   if (fixP->fx_r_type == BFD_RELOC_XTENSA_ASM_EXPAND)
-    return addr;
+    return 0;
 
   if (!insnbuf)
     {
@@ -5482,7 +5351,7 @@ md_pcrel_from (fixS *fixP)
     }
 
   insn_p = &fixP->fx_frag->fr_literal[fixP->fx_where];
-  xtensa_insnbuf_from_chars (isa, insnbuf, insn_p, 0);
+  xtensa_insnbuf_from_chars (isa, insnbuf, (unsigned char *) insn_p, 0);
   fmt = xtensa_format_decode (isa, insnbuf);
 
   if (fmt == XTENSA_UNDEFINED)
@@ -5494,14 +5363,15 @@ md_pcrel_from (fixS *fixP)
   xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf);
   opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf);
 
-  /* Check for "alternate" relocation (operand not specified).  */
+  /* Check for "alternate" relocations (operand not specified).  None
+     of the current uses for these are really PC-relative.  */
   if (alt_reloc || opcode == xtensa_const16_opcode)
     {
       if (opcode != xtensa_l32r_opcode
          && opcode != xtensa_const16_opcode)
        as_fatal (_("invalid relocation for '%s' instruction"),
                  xtensa_opcode_name (isa, opcode));
-      return addr;
+      return 0;
     }
 
   opnum = get_relaxable_immed (opcode);
@@ -5513,7 +5383,7 @@ md_pcrel_from (fixS *fixP)
                    fixP->fx_line,
                    _("invalid relocation for operand %d of '%s'"),
                    opnum, xtensa_opcode_name (isa, opcode));
-      return addr;
+      return 0;
     }
   return 0 - opnd_value;
 }
@@ -5525,7 +5395,8 @@ int
 xtensa_force_relocation (fixS *fix)
 {
   switch (fix->fx_r_type)
-   {
+    {
+    case BFD_RELOC_XTENSA_ASM_EXPAND:
     case BFD_RELOC_XTENSA_SLOT0_ALT:
     case BFD_RELOC_XTENSA_SLOT1_ALT:
     case BFD_RELOC_XTENSA_SLOT2_ALT:
@@ -5541,8 +5412,6 @@ xtensa_force_relocation (fixS *fix)
     case BFD_RELOC_XTENSA_SLOT12_ALT:
     case BFD_RELOC_XTENSA_SLOT13_ALT:
     case BFD_RELOC_XTENSA_SLOT14_ALT:
-    case BFD_RELOC_VTABLE_INHERIT:
-    case BFD_RELOC_VTABLE_ENTRY:
       return 1;
     default:
       break;
@@ -5556,6 +5425,33 @@ xtensa_force_relocation (fixS *fix)
 }
 
 
+/* TC_VALIDATE_FIX_SUB hook */
+
+int
+xtensa_validate_fix_sub (fixS *fix)
+{
+  segT add_symbol_segment, sub_symbol_segment;
+
+  /* The difference of two symbols should be resolved by the assembler when
+     linkrelax is not set.  If the linker may relax the section containing
+     the symbols, then an Xtensa DIFF relocation must be generated so that
+     the linker knows to adjust the difference value.  */
+  if (!linkrelax || fix->fx_addsy == NULL)
+    return 0;
+
+  /* Make sure both symbols are in the same segment, and that segment is
+     "normal" and relaxable.  If the segment is not "normal", then the
+     fix is not valid.  If the segment is not "relaxable", then the fix
+     should have been handled earlier.  */
+  add_symbol_segment = S_GET_SEGMENT (fix->fx_addsy);
+  if (! SEG_NORMAL (add_symbol_segment) ||
+      ! relaxable_section (add_symbol_segment))
+    return 0;
+  sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy);
+  return (sub_symbol_segment == add_symbol_segment);
+}
+
+
 /* NO_PSEUDO_DOT hook */
 
 /* This function has nothing to do with pseudo dots, but this is the
@@ -5603,59 +5499,142 @@ xtensa_fix_adjustable (fixS *fixP)
       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 0;
 
-  if (fixP->fx_addsy
-      && (S_IS_EXTERNAL (fixP->fx_addsy) || S_IS_WEAK (fixP->fx_addsy)))
-    return 0;
-
-#if 0
-  /* We may someday want to enable this code to preserve relocations for
-     non-PC-relative fixes, possibly under control of a PIC flag.  */
-  return (fixP->fx_pcrel
-         || (fixP->fx_subsy != NULL
-             && (S_GET_SEGMENT (fixP->fx_subsy)
-                 == S_GET_SEGMENT (fixP->fx_addsy)))
-         || S_IS_LOCAL (fixP->fx_addsy));
-#else
   return 1;
-#endif
 }
 
 
 void
-md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 {
-  if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0)
-    {
-      char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
+  char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
+  valueT val = 0;
 
-      switch (fixP->fx_r_type)
+  /* 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_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+
+  switch (fixP->fx_r_type)
+    {
+    case BFD_RELOC_32:
+    case BFD_RELOC_16:
+    case BFD_RELOC_8:
+      if (fixP->fx_subsy)
        {
-       case BFD_RELOC_XTENSA_ASM_EXPAND:
-         fixP->fx_done = 1;
-         break;
+         switch (fixP->fx_r_type)
+           {
+           case BFD_RELOC_8:
+             fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
+             break;
+           case BFD_RELOC_16:
+             fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
+             break;
+           case BFD_RELOC_32:
+             fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
+             break;
+           default:
+             break;
+           }
 
-       case BFD_RELOC_XTENSA_ASM_SIMPLIFY:
-         as_bad (_("unhandled local relocation fix %s"),
-                 bfd_get_reloc_code_name (fixP->fx_r_type));
-         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"));
 
-       case BFD_RELOC_32:
-       case BFD_RELOC_16:
-       case BFD_RELOC_8:
-         /* The only one we support that isn't an instruction field.  */
-         md_number_to_chars (fixpos, *valP, fixP->fx_size);
+         val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
+                - S_GET_VALUE (fixP->fx_subsy));
+
+         /* The difference value gets written out, and the DIFF reloc
+            identifies the address of the subtracted symbol (i.e., the one
+            with the lowest address).  */
+         *valP = val;
+         fixP->fx_offset -= val;
+         fixP->fx_subsy = NULL;
+       }
+      else if (! fixP->fx_addsy)
+       {
+         val = *valP;
          fixP->fx_done = 1;
-         break;
+       }
+      /* fall through */
 
-       case BFD_RELOC_VTABLE_INHERIT:
-       case BFD_RELOC_VTABLE_ENTRY:
-         fixP->fx_done = 0;
-         break;
+    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;
 
-       default:
-         as_bad (_("unhandled local relocation fix %s"),
-                 bfd_get_reloc_code_name (fixP->fx_r_type));
+    case BFD_RELOC_XTENSA_SLOT0_OP:
+    case BFD_RELOC_XTENSA_SLOT1_OP:
+    case BFD_RELOC_XTENSA_SLOT2_OP:
+    case BFD_RELOC_XTENSA_SLOT3_OP:
+    case BFD_RELOC_XTENSA_SLOT4_OP:
+    case BFD_RELOC_XTENSA_SLOT5_OP:
+    case BFD_RELOC_XTENSA_SLOT6_OP:
+    case BFD_RELOC_XTENSA_SLOT7_OP:
+    case BFD_RELOC_XTENSA_SLOT8_OP:
+    case BFD_RELOC_XTENSA_SLOT9_OP:
+    case BFD_RELOC_XTENSA_SLOT10_OP:
+    case BFD_RELOC_XTENSA_SLOT11_OP:
+    case BFD_RELOC_XTENSA_SLOT12_OP:
+    case BFD_RELOC_XTENSA_SLOT13_OP:
+    case BFD_RELOC_XTENSA_SLOT14_OP:
+      if (linkrelax)
+       {
+         /* Write the tentative value of a PC-relative relocation to a
+            local symbol into the instruction.  The value will be ignored
+            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
+             && !S_FORCE_RELOC (fixP->fx_addsy, 1))
+           {
+             val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
+                    - md_pcrel_from (fixP));
+             (void) xg_apply_fix_value (fixP, val);
+           }
+       }
+      else if (! fixP->fx_addsy)
+       {
+         val = *valP;
+         if (xg_apply_fix_value (fixP, val))
+           fixP->fx_done = 1;
        }
+      break;
+
+    case BFD_RELOC_XTENSA_ASM_EXPAND:
+    case BFD_RELOC_XTENSA_SLOT0_ALT:
+    case BFD_RELOC_XTENSA_SLOT1_ALT:
+    case BFD_RELOC_XTENSA_SLOT2_ALT:
+    case BFD_RELOC_XTENSA_SLOT3_ALT:
+    case BFD_RELOC_XTENSA_SLOT4_ALT:
+    case BFD_RELOC_XTENSA_SLOT5_ALT:
+    case BFD_RELOC_XTENSA_SLOT6_ALT:
+    case BFD_RELOC_XTENSA_SLOT7_ALT:
+    case BFD_RELOC_XTENSA_SLOT8_ALT:
+    case BFD_RELOC_XTENSA_SLOT9_ALT:
+    case BFD_RELOC_XTENSA_SLOT10_ALT:
+    case BFD_RELOC_XTENSA_SLOT11_ALT:
+    case BFD_RELOC_XTENSA_SLOT12_ALT:
+    case BFD_RELOC_XTENSA_SLOT13_ALT:
+    case BFD_RELOC_XTENSA_SLOT14_ALT:
+      /* These all need to be resolved at link-time.  Do nothing now.  */
+      break;
+
+    case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_VTABLE_ENTRY:
+      fixP->fx_done = 0;
+      break;
+
+    default:
+      as_bad (_("unhandled local relocation fix %s"),
+             bfd_get_reloc_code_name (fixP->fx_r_type));
     }
 }
 
@@ -5706,7 +5685,7 @@ md_atof (int type, char *litP, int *sizeP)
 int
 md_estimate_size_before_relax (fragS *fragP, segT seg ATTRIBUTE_UNUSED)
 {
-  return fragP->tc_frag_data.text_expansion[0];
+  return total_frag_text_expansion (fragP);
 }
 
 
@@ -5714,10 +5693,9 @@ md_estimate_size_before_relax (fragS *fragP, segT seg ATTRIBUTE_UNUSED)
    format.  */
 
 arelent *
-tc_gen_reloc (asection *section, fixS *fixp)
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 {
   arelent *reloc;
-  bfd_boolean apply_tentative_value = FALSE;
 
   reloc = (arelent *) xmalloc (sizeof (arelent));
   reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
@@ -5728,128 +5706,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
      They'd better have been fully resolved by this point.  */
   assert ((int) fixp->fx_r_type > 0);
 
-  if (linkrelax && fixp->fx_subsy
-      && (fixp->fx_r_type == BFD_RELOC_8
-         || fixp->fx_r_type == BFD_RELOC_16
-         || fixp->fx_r_type == BFD_RELOC_32))
-    {
-      int diff_size = 0;
-      bfd_vma diff_value, diff_mask = 0;
-
-      switch (fixp->fx_r_type)
-       {
-       case BFD_RELOC_8:
-         fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
-         diff_size = 1;
-         diff_mask = 0xff;
-         break;
-       case BFD_RELOC_16:
-         fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
-         diff_size = 2;
-         diff_mask = 0xffff;
-         break;
-       case BFD_RELOC_32:
-         fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
-         diff_size = 4;
-         diff_mask = 0xffffffff;
-         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"));
-         free (reloc->sym_ptr_ptr);
-         free (reloc);
-         return NULL;
-       }
-
-      assert (S_GET_SEGMENT (fixp->fx_addsy)
-             == S_GET_SEGMENT (fixp->fx_subsy));
-
-      diff_value = (S_GET_VALUE (fixp->fx_addsy) + fixp->fx_offset
-                   - S_GET_VALUE (fixp->fx_subsy));
-
-      /* Check for overflow.  */
-      if ((diff_value & ~diff_mask) != 0)
-       {
-         as_bad_where (fixp->fx_file, fixp->fx_line,
-                       _("value of %ld too large"), diff_value);
-         free (reloc->sym_ptr_ptr);
-         free (reloc);
-         return NULL;
-       }
-
-      md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
-                         diff_value, diff_size);
-      reloc->addend = fixp->fx_offset - diff_value;
-    }
-  else
-    {
-      reloc->addend = fixp->fx_offset;
-
-      switch (fixp->fx_r_type)
-       {
-       case BFD_RELOC_XTENSA_SLOT0_OP:
-       case BFD_RELOC_XTENSA_SLOT1_OP:
-       case BFD_RELOC_XTENSA_SLOT2_OP:
-       case BFD_RELOC_XTENSA_SLOT3_OP:
-       case BFD_RELOC_XTENSA_SLOT4_OP:
-       case BFD_RELOC_XTENSA_SLOT5_OP:
-       case BFD_RELOC_XTENSA_SLOT6_OP:
-       case BFD_RELOC_XTENSA_SLOT7_OP:
-       case BFD_RELOC_XTENSA_SLOT8_OP:
-       case BFD_RELOC_XTENSA_SLOT9_OP:
-       case BFD_RELOC_XTENSA_SLOT10_OP:
-       case BFD_RELOC_XTENSA_SLOT11_OP:
-       case BFD_RELOC_XTENSA_SLOT12_OP:
-       case BFD_RELOC_XTENSA_SLOT13_OP:
-       case BFD_RELOC_XTENSA_SLOT14_OP:
-         /* As a special case, the immediate value for a CONST16 opcode
-            should not be applied, since this kind of relocation is
-            handled specially for CONST16 and is not really PC-relative.
-            Rather than decode the opcode here, just wait and handle it
-            in xg_apply_tentative_value.  */
-         apply_tentative_value = TRUE;
-         break;
-
-       case BFD_RELOC_XTENSA_SLOT0_ALT:
-       case BFD_RELOC_XTENSA_SLOT1_ALT:
-       case BFD_RELOC_XTENSA_SLOT2_ALT:
-       case BFD_RELOC_XTENSA_SLOT3_ALT:
-       case BFD_RELOC_XTENSA_SLOT4_ALT:
-       case BFD_RELOC_XTENSA_SLOT5_ALT:
-       case BFD_RELOC_XTENSA_SLOT6_ALT:
-       case BFD_RELOC_XTENSA_SLOT7_ALT:
-       case BFD_RELOC_XTENSA_SLOT8_ALT:
-       case BFD_RELOC_XTENSA_SLOT9_ALT:
-       case BFD_RELOC_XTENSA_SLOT10_ALT:
-       case BFD_RELOC_XTENSA_SLOT11_ALT:
-       case BFD_RELOC_XTENSA_SLOT12_ALT:
-       case BFD_RELOC_XTENSA_SLOT13_ALT:
-       case BFD_RELOC_XTENSA_SLOT14_ALT:
-       case BFD_RELOC_XTENSA_ASM_EXPAND:
-       case BFD_RELOC_32:
-       case BFD_RELOC_XTENSA_PLT:
-       case BFD_RELOC_VTABLE_INHERIT:
-       case BFD_RELOC_VTABLE_ENTRY:
-         break;
-
-       case BFD_RELOC_XTENSA_ASM_SIMPLIFY:
-         as_warn (_("emitting simplification relocation"));
-         break;
-
-       default:
-         as_warn (_("emitting unknown relocation"));
-       }
-    }
+  reloc->addend = fixp->fx_offset;
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
   if (reloc->howto == NULL)
@@ -5866,35 +5723,17 @@ tc_gen_reloc (asection *section, fixS *fixp)
     as_fatal (_("internal error? cannot generate `%s' relocation"),
              bfd_get_reloc_code_name (fixp->fx_r_type));
 
-  /* Write the tentative value of a PC-relative relocation to a local symbol
-     into the instruction.  The value will be ignored by the linker, and it
-     makes the object file disassembly readable when the linkrelax flag is
-     set and all branch targets are encoded in relocations.  */
-
-  if (linkrelax && apply_tentative_value && fixp->fx_pcrel)
-    {
-      valueT val;
-      assert (fixp->fx_addsy);
-      if (S_GET_SEGMENT (fixp->fx_addsy) == section && !fixp->fx_plt
-         && !S_FORCE_RELOC (fixp->fx_addsy, 1))
-       {
-         val = (S_GET_VALUE (fixp->fx_addsy) + fixp->fx_offset
-                - md_pcrel_from (fixp));
-         xg_apply_tentative_value (fixp, val);
-       }
-    }
-
   return reloc;
 }
 
 \f
 /* Checks for resource conflicts between instructions.  */
 
-/* The func unit stuff could be implemented as bit-vectors rather 
-   than the iterative approach here.  If it ends up being too 
+/* The func unit stuff could be implemented as bit-vectors rather
+   than the iterative approach here.  If it ends up being too
    slow, we will switch it.  */
 
-resource_table * 
+resource_table *
 new_resource_table (void *data,
                    int cycles,
                    int nu,
@@ -5914,15 +5753,15 @@ new_resource_table (void *data,
   rt->opcode_unit_use = ouuf;
   rt->opcode_unit_stage = ousf;
 
-  rt->units = (char **) xcalloc (cycles, sizeof (char *));
+  rt->units = (unsigned char **) xcalloc (cycles, sizeof (unsigned char *));
   for (i = 0; i < cycles; i++)
-    rt->units[i] = (char *) xcalloc (nu, sizeof (char));
+    rt->units[i] = (unsigned char *) xcalloc (nu, sizeof (unsigned char));
 
   return rt;
 }
 
 
-void 
+void
 clear_resource_table (resource_table *rt)
 {
   int i, j;
@@ -5934,7 +5773,7 @@ clear_resource_table (resource_table *rt)
 
 /* We never shrink it, just fake it into thinking so.  */
 
-void 
+void
 resize_resource_table (resource_table *rt, int cycles)
 {
   int i, old_cycles;
@@ -5946,21 +5785,23 @@ resize_resource_table (resource_table *rt, int cycles)
   old_cycles = rt->allocated_cycles;
   rt->allocated_cycles = cycles;
 
-  rt->units = xrealloc (rt->units, sizeof (char *) * rt->allocated_cycles);
+  rt->units = xrealloc (rt->units,
+                       rt->allocated_cycles * sizeof (unsigned char *));
   for (i = 0; i < old_cycles; i++)
-    rt->units[i] = xrealloc (rt->units[i], sizeof (char) * rt->num_units);
+    rt->units[i] = xrealloc (rt->units[i],
+                            rt->num_units * sizeof (unsigned char));
   for (i = old_cycles; i < cycles; i++)
-    rt->units[i] = xcalloc (rt->num_units, sizeof (char));
+    rt->units[i] = xcalloc (rt->num_units, sizeof (unsigned char));
 }
 
 
-bfd_boolean 
+bfd_boolean
 resources_available (resource_table *rt, xtensa_opcode opcode, int cycle)
 {
   int i;
   int uses = (rt->opcode_num_units) (rt->data, opcode);
 
-  for (i = 0; i < uses; i++) 
+  for (i = 0; i < uses; i++)
     {
       xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i);
       int stage = (rt->opcode_unit_stage) (rt->data, opcode, i);
@@ -5971,20 +5812,20 @@ resources_available (resource_table *rt, xtensa_opcode opcode, int cycle)
     }
   return TRUE;
 }
-     
 
-void 
+
+void
 reserve_resources (resource_table *rt, xtensa_opcode opcode, int cycle)
 {
   int i;
   int uses = (rt->opcode_num_units) (rt->data, opcode);
 
-  for (i = 0; i < uses; i++) 
+  for (i = 0; i < uses; i++)
     {
       xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i);
       int stage = (rt->opcode_unit_stage) (rt->data, opcode, i);
-      /* Note that this allows resources to be oversubscribed.  That's 
-        essential to the way the optional scheduler works. 
+      /* Note that this allows resources to be oversubscribed.  That's
+        essential to the way the optional scheduler works.
         resources_available reports when a resource is over-subscribed,
         so it's easy to tell.  */
       rt->units[stage + cycle][unit]++;
@@ -5992,34 +5833,34 @@ reserve_resources (resource_table *rt, xtensa_opcode opcode, int cycle)
 }
 
 
-void 
+void
 release_resources (resource_table *rt, xtensa_opcode opcode, int cycle)
 {
   int i;
   int uses = (rt->opcode_num_units) (rt->data, opcode);
 
-  for (i = 0; i < uses; i++) 
+  for (i = 0; i < uses; i++)
     {
       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);
       rt->units[stage + cycle][unit]--;
-      assert (rt->units[stage + cycle][unit] >= 0);
     }
 }
-     
+
 
 /* Wrapper functions make parameterized resource reservation
    more convenient.  */
 
-int 
+int
 opcode_funcUnit_use_unit (void *data, xtensa_opcode opcode, int idx)
 {
   xtensa_funcUnit_use *use = xtensa_opcode_funcUnit_use (data, opcode, idx);
-  return use->unit;  
+  return use->unit;
 }
 
 
-int 
+int
 opcode_funcUnit_use_stage (void *data, xtensa_opcode opcode, int idx)
 {
   xtensa_funcUnit_use *use = xtensa_opcode_funcUnit_use (data, opcode, idx);
@@ -6029,9 +5870,9 @@ opcode_funcUnit_use_stage (void *data, xtensa_opcode opcode, int idx)
 
 /* Note that this function does not check issue constraints, but
    solely whether the hardware is available to execute the given
-   instructions together.  It also doesn't check if the tinsns 
+   instructions together.  It also doesn't check if the tinsns
    write the same state, or access the same tieports.  That is
-   checked by check_t1_t2_read_write.  */
+   checked by check_t1_t2_reads_and_writes.  */
 
 static bfd_boolean
 resources_conflict (vliw_insn *vinsn)
@@ -6043,7 +5884,7 @@ resources_conflict (vliw_insn *vinsn)
   if (vinsn->num_slots == 1)
     return FALSE;
 
-  if (rt == NULL) 
+  if (rt == NULL)
     {
       xtensa_isa isa = xtensa_default_isa;
       rt = new_resource_table
@@ -6072,7 +5913,6 @@ resources_conflict (vliw_insn *vinsn)
 
 static bfd_boolean 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 *);
 
 
@@ -6084,10 +5924,13 @@ finish_vinsn (vliw_insn *vinsn)
   IStack slotstack;
   int i;
   char *file_name;
-  int line;
+  unsigned line;
 
   if (find_vinsn_conflicts (vinsn))
-    return;
+    {
+      xg_clear_vinsn (vinsn);
+      return;
+    }
 
   /* First, find a format that works.  */
   if (vinsn->format == XTENSA_UNDEFINED)
@@ -6119,7 +5962,7 @@ finish_vinsn (vliw_insn *vinsn)
       return;
     }
 
-  if (resources_conflict (vinsn)) 
+  if (resources_conflict (vinsn))
     {
       as_where (&file_name, &line);
       as_bad_where (file_name, line, _("illegal resource usage in bundle"));
@@ -6169,7 +6012,7 @@ finish_vinsn (vliw_insn *vinsn)
              return;
            }
 
-         for (j = 0; j < slotstack.ninsn - 1; j++)
+         for (j = 0; j < slotstack.ninsn; j++)
            {
              TInsn *insn = &slotstack.insn[j];
              if (insn->insn_type == ITYPE_LITERAL)
@@ -6179,9 +6022,11 @@ finish_vinsn (vliw_insn *vinsn)
                }
              else
                {
+                 assert (insn->insn_type == ITYPE_INSN);
                  if (lit_sym)
                    xg_resolve_literals (insn, lit_sym);
-                 emit_single_op (insn);
+                 if (j != slotstack.ninsn - 1)
+                   emit_single_op (insn);
                }
            }
 
@@ -6195,11 +6040,11 @@ 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
-                   vinsn->slots[i].opcode 
+                   vinsn->slots[i].opcode
                      = xtensa_format_slot_nop_opcode (xtensa_default_isa,
                                                       vinsn->format, i);
 
@@ -6215,7 +6060,7 @@ finish_vinsn (vliw_insn *vinsn)
     }
 
   /* Now check resource conflicts on the modified bundle.  */
-  if (resources_conflict (vinsn)) 
+  if (resources_conflict (vinsn))
     {
       as_where (&file_name, &line);
       as_bad_where (file_name, line, _("illegal resource usage in bundle"));
@@ -6315,12 +6160,12 @@ find_vinsn_conflicts (vliw_insn *vinsn)
                          xtensa_opcode_name (isa, op2->opcode), j);
                  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;
                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;
@@ -6344,17 +6189,17 @@ find_vinsn_conflicts (vliw_insn *vinsn)
 }
 
 
-/* Check how the result registers of t1 and t2 relate.
+/* Check how the state used by t1 and t2 relate.
    Cases found are:
 
    case A: t1 reads a register t2 writes (an antidependency within a bundle)
    case B: no relationship between what is read and written (both could
            read the same reg though)
-   case C: t1 writes a register t2 writes (a register conflict within a 
+   case C: t1 writes a register t2 writes (a register conflict within a
            bundle)
    case D: t1 writes a state that t2 also writes
    case E: t1 writes a tie queue that t2 also writes
-   case F: two volatile queue writes
+   case F: two volatile queue accesses
 */
 
 static char
@@ -6450,7 +6295,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)
            continue;
 
          if (t2_inout == 'i' && (t1_inout == 'm' || t1_inout == 'o'))
@@ -6458,61 +6303,64 @@ check_t1_t2_reads_and_writes (TInsn *t1, TInsn *t2)
              conflict = 'a';
              continue;
            }
-         
+
          if (t1_inout == 'i' && (t2_inout == 'm' || t2_inout == 'o'))
            {
              conflict = 'a';
              continue;
            }
-         
+
          if (t1_inout != 'i' && t2_inout != 'i')
            return 'd';
-       }      
+       }
     }
 
   /* Check tieports.  */
   t1_interfaces = xtensa_opcode_num_interfaceOperands (isa, t1->opcode);
   t2_interfaces = xtensa_opcode_num_interfaceOperands (isa, t2->opcode);
-  for (j = 0; j < t2_interfaces; j++) 
+  for (j = 0; j < t2_interfaces; j++)
     {
       xtensa_interface t2_int
        = xtensa_interfaceOperand_interface (isa, t2->opcode, j);
-      t2_inout = xtensa_interface_inout (isa, j);
-      if (xtensa_interface_has_side_effect (isa, t2_int) == 1 
-         && t2_inout != 'i')
+      int t2_class = xtensa_interface_class_id (isa, t2_int);
+
+      t2_inout = xtensa_interface_inout (isa, t2_int);
+      if (xtensa_interface_has_side_effect (isa, t2_int) == 1)
        t2_volatile = TRUE;
+
       for (i = 0; i < t1_interfaces; i++)
        {
          xtensa_interface t1_int
            = xtensa_interfaceOperand_interface (isa, t1->opcode, j);
-         t1_inout = xtensa_interface_inout (isa, i);
-         if (xtensa_interface_has_side_effect (isa, t1_int) == 1 
-             && t1_inout != 'i')
+         int t1_class = xtensa_interface_class_id (isa, t1_int);
+
+         t1_inout = xtensa_interface_inout (isa, t1_int);
+         if (xtensa_interface_has_side_effect (isa, t1_int) == 1)
            t1_volatile = TRUE;
-         
+
+         if (t1_volatile && t2_volatile && (t1_class == t2_class))
+           return 'f';
+
          if (t1_int != t2_int)
            continue;
-         
+
          if (t2_inout == 'i' && t1_inout == 'o')
            {
              conflict = 'a';
              continue;
            }
-         
+
          if (t1_inout == 'i' && t2_inout == 'o')
            {
              conflict = 'a';
              continue;
            }
-         
+
          if (t1_inout != 'i' && t2_inout != 'i')
            return 'e';
        }
     }
 
-  if (t1_volatile && t2_volatile)
-    return 'f';
-  
   return conflict;
 }
 
@@ -6530,6 +6378,9 @@ xg_find_narrowest_format (vliw_insn *vinsn)
   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;
@@ -6555,22 +6406,11 @@ xg_find_narrowest_format (vliw_insn *vinsn)
                  /* Try the widened version.  */
                  if (!v_copy.slots[slot].keep_wide
                      && !v_copy.slots[slot].is_specific_opcode
-                     && xg_is_narrow_insn (&v_copy.slots[slot])
-                     && !xg_expand_narrow (&widened, &v_copy.slots[slot])
+                     && xg_is_single_relaxable_insn (&v_copy.slots[slot],
+                                                     &widened, TRUE)
                      && opcode_fits_format_slot (widened.opcode,
                                                  format, slot))
                    {
-                     /* The xg_is_narrow clause requires some explanation:
-
-                        addi can be "widened" to an addmi, which is then
-                        expanded to an addmi/addi pair if the immediate
-                        requires it, but here we must have a single widen
-                        only.
-
-                        xg_is_narrow tells us that addi isn't really
-                        narrow.  The widen_spec_list says that there are
-                        other cases.  */
-
                      v_copy.slots[slot] = widened;
                      fit++;
                    }
@@ -6599,8 +6439,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, bfd_boolean *pfinish_frag)
 {
+  bfd_boolean finish_frag = FALSE;
   int extra_space = 0;
   int slot;
 
@@ -6611,20 +6452,13 @@ relaxation_requirements (vliw_insn *vinsn)
        {
          /* A narrow instruction could be widened later to help
             alignment issues.  */
-         if (xg_is_narrow_insn (tinsn)
+         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
@@ -6637,7 +6471,7 @@ relaxation_requirements (vliw_insn *vinsn)
              extra_space += 3; /* for the nop size */
              tinsn->subtype = RELAX_ADD_NOP_IF_PRE_LOOP_END;
            }
-         
+
          /* Need to assemble it with space for the relocation.  */
          if (xg_is_relaxable_insn (tinsn, 0)
              && !tinsn->is_specific_opcode)
@@ -6645,59 +6479,48 @@ relaxation_requirements (vliw_insn *vinsn)
              int max_size = xg_get_max_insn_widen_size (tinsn->opcode);
              int max_literal_size =
                xg_get_max_insn_widen_literal_size (tinsn->opcode);
-             
+
              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);
+  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);
 }
 
 
@@ -6712,14 +6535,15 @@ emit_single_op (TInsn *orig_insn)
   istack_init (&istack);
 
   /* Special-case for "movi aX, foo" which is guaranteed to need relaxing.
-     Because the scheduling and bundling characteristics of movi and 
-     l32r or const16 are so different, we can do much better if we relax 
+     Because the scheduling and bundling characteristics of movi and
+     l32r or const16 are so different, we can do much better if we relax
      it prior to scheduling and bundling, rather than after.  */
-  if ((orig_insn->opcode == xtensa_movi_opcode 
+  if ((orig_insn->opcode == xtensa_movi_opcode
        || 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->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))
@@ -6728,7 +6552,7 @@ emit_single_op (TInsn *orig_insn)
   for (i = 0; i < istack.ninsn; i++)
     {
       TInsn *insn = &istack.insn[i];
-      switch (insn->insn_type) 
+      switch (insn->insn_type)
        {
        case ITYPE_LITERAL:
          assert (lit_sym == NULL);
@@ -6747,11 +6571,17 @@ emit_single_op (TInsn *orig_insn)
          }
          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);
@@ -6762,12 +6592,25 @@ emit_single_op (TInsn *orig_insn)
 }
 
 
+static int
+total_frag_text_expansion (fragS *fragP)
+{
+  int slot;
+  int total_expansion = 0;
+
+  for (slot = 0; slot < MAX_SLOTS; slot++)
+    total_expansion += fragP->tc_frag_data.text_expansion[slot];
+
+  return total_expansion;
+}
+
+
 /* Emit a vliw instruction to the current fragment.  */
 
 static void
 xg_assemble_vliw_tokens (vliw_insn *vinsn)
 {
-  bfd_boolean finish_frag = FALSE;
+  bfd_boolean finish_frag;
   bfd_boolean is_jump = FALSE;
   bfd_boolean is_branch = FALSE;
   xtensa_isa isa = xtensa_default_isa;
@@ -6776,9 +6619,10 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
   int extra_space;
   char *f = NULL;
   int slot;
-  struct dwarf2_line_info best_loc;
+  unsigned current_line, best_linenum;
+  char *current_file;
 
-  best_loc.line = INT_MAX;
+  best_linenum = UINT_MAX;
 
   if (generating_literals)
     {
@@ -6796,6 +6640,8 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
       && (! frag_now->tc_frag_data.is_insn
          || (vinsn_has_specific_opcodes (vinsn) && use_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]
              != frag_now->tc_frag_data.use_absolute_literals)))
     {
@@ -6836,44 +6682,47 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
       /* See if the instruction implies an aligned section.  */
       if (xtensa_opcode_is_loop (isa, vinsn->slots[i].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;
+      best_linenum = vinsn->slots[i].linenum < best_linenum
+       ? vinsn->slots[i].linenum : best_linenum;
     }
 
   /* Special cases for instructions that force an alignment... */
   /* None of these opcodes are bundle-able.  */
   if (xtensa_opcode_is_loop (isa, vinsn->slots[0].opcode) == 1)
     {
-      size_t max_fill;
-      
+      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;
-      
+
       max_fill = get_text_align_max_fill_size
        (get_text_align_power (xtensa_fetch_width),
         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);
+       frag_var (rs_machine_dependent, 0, 0,
+                 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);
     }
 
@@ -6891,31 +6740,35 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
 
   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 = (char *) frag_more (insn_size + extra_space);
+      f = frag_more (insn_size + extra_space);
       xtensa_set_frag_assembly_state (frag_now);
       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, f, 0);
-  
-  xtensa_dwarf2_emit_insn (insn_size - extra_space, &best_loc);
+  xtensa_insnbuf_to_chars (isa, vinsn->insnbuf, (unsigned char *) f, 0);
+
+  /* Temporarily set the logical line number to the one we want to appear
+     in the debug information.  */
+  as_where (&current_file, &current_line);
+  new_logical_line (current_file, best_linenum);
+  dwarf2_emit_insn (insn_size + extra_space);
+  new_logical_line (current_file, current_line);
 
   for (slot = 0; slot < vinsn->num_slots; slot++)
     {
       TInsn *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.slot_symbols[slot] = tinsn->symbol;
+      frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset;
       frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag;
       if (tinsn->literal_space != 0)
        xg_assemble_literal_space (tinsn->literal_space, slot);
@@ -6927,8 +6780,8 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
       if (xtensa_opcode_is_branch (isa, tinsn->opcode) == 1)
        is_branch = TRUE;
 
-      if (tinsn->subtype || tinsn->symbol || tinsn->record_fix 
-         || tinsn->offset || tinsn->literal_frag || is_jump || is_branch)
+      if (tinsn->subtype || tinsn->symbol || tinsn->offset
+         || tinsn->literal_frag || is_jump || is_branch)
        finish_frag = TRUE;
     }
 
@@ -6949,7 +6802,7 @@ 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 ())
@@ -6988,7 +6841,7 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
                    frag_now->fr_symbol, frag_now->fr_offset, NULL);
          xtensa_set_frag_assembly_state (frag_now);
        }
-      else if (is_branch && align_targets)
+      else if (is_branch && do_align_targets ())
        {
          assert (finish_frag);
          frag_var (rs_machine_dependent,
@@ -7035,6 +6888,7 @@ 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)
@@ -7060,10 +6914,13 @@ 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 ();
 }
 
 
@@ -7071,126 +6928,80 @@ static void
 xtensa_cleanup_align_frags (void)
 {
   frchainS *frchP;
+  asection *s;
 
-  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;
-
-             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;
-       }
-    }
+  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.
-   If the next fragment starts with a loop target, AND the previous
-   fragment can be expanded to negate the branch, convert this to a
-   RELAX_LOOP_END.  Otherwise, convert to a .fill 0.  */
-
-static bfd_boolean frag_can_negate_branch (fragS *);
+   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 (frchP = frchain_root; frchP; frchP = frchP->frch_next)
-    {
-      bfd_boolean prev_frag_can_negate_branch = FALSE;
-      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_loop_target (fragP))
-               {
-                 if (prev_frag_can_negate_branch)
-                   {
-                     fragP->fr_subtype = RELAX_LOOP_END;
-                     /* See the comment near the frag_var with a
-                        RELAX_DESIRE_ALIGN to see why we do this.  */
-                     fragP->fr_var = RELAX_LOOP_END_BYTES;
-                   }
-                 else
-                   {
-                     if (next_frag_is_branch_target (fragP))
-                       fragP->fr_subtype = RELAX_DESIRE_ALIGN;
-                     else
-                       frag_wane (fragP);
-                   }
-               }
-             else if (next_frag_is_branch_target (fragP))
-               fragP->fr_subtype = RELAX_DESIRE_ALIGN;
-             else
-               frag_wane (fragP);
-           }
-         if (fragP->fr_fix != 0)
-           prev_frag_can_negate_branch = FALSE;
-         if (frag_can_negate_branch (fragP))
-           prev_frag_can_negate_branch = TRUE;
-       }
-    }
-}
-
-
-static bfd_boolean
-frag_can_negate_branch (fragS *fragP)
-{
-  xtensa_isa isa = xtensa_default_isa;
-  vliw_insn vinsn;
-  int slot;
-
-  if (fragP->fr_type != rs_machine_dependent
-      || fragP->fr_subtype != RELAX_SLOTS)
-    return FALSE;
-
-  vinsn_from_chars (&vinsn, fragP->fr_opcode);
-
-  for (slot = 0; slot < xtensa_format_num_slots (isa, vinsn.format); slot++)
-    {
-      if ((fragP->tc_frag_data.slot_subtypes[slot] == RELAX_IMMED)
-         && xtensa_opcode_is_branch (isa, vinsn.slots[slot].opcode) == 1)
-       return TRUE;
-    }
+  for (s = stdoutput->sections; s; s = s->next)
+    for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
+      {
+       fragS *fragP;
 
-  return FALSE;
+       /* 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);
+             }
+         }
+      }
 }
 
 
@@ -7200,40 +7011,38 @@ static void
 xtensa_mark_narrow_branches (void)
 {
   frchainS *frchP;
+  asection *s;
 
-  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_machine_dependent
-             && fragP->fr_subtype == RELAX_SLOTS
-             && fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED)
-           {
-             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;
-               }
-           }
-       }
-    }
+  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;
+                 }
+             }
+         }
+      }
 }
 
 
@@ -7247,18 +7056,27 @@ xtensa_mark_narrow_branches (void)
    use for alignment narrow branches that definitely will not expand to a
    jump and a branch.  These functions find and mark these cases.  */
 
-/* the range in bytes of a bnez.n and beqz.n */
-#define MAX_IMMED6 68
+/* The range in bytes of BNEZ.N and BEQZ.N.  The target operand is encoded
+   as PC + 4 + imm6, where imm6 is a 6-bit immediate ranging from 0 to 63.
+   We start counting beginning with the frag after the 2-byte branch, so the
+   maximum offset is (4 - 2) + 63 = 65.  */
+#define MAX_IMMED6 65
 
-static size_t unrelaxed_frag_max_size (fragS *);
+static offsetT unrelaxed_frag_max_size (fragS *);
 
 static bfd_boolean
 is_narrow_branch_guaranteed_in_range (fragS *fragP, TInsn *tinsn)
 {
   const expressionS *expr = &tinsn->tok[1];
   symbolS *symbolP = expr->X_add_symbol;
-  fragS *target_frag = symbol_get_frag (symbolP);
-  size_t max_distance = expr->X_add_number;
+  offsetT max_distance = expr->X_add_number;
+  fragS *target_frag;
+
+  if (expr->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;
@@ -7281,33 +7099,50 @@ static void
 xtensa_mark_zcl_first_insns (void)
 {
   frchainS *frchP;
+  asection *s;
 
-  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_machine_dependent
-             && (fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE
-                 || fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE))
-           {
-             /* 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);
-               }
-           }
-       }
-    }
+  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 *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;
+                   /* 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);
+             }
+         }
+      }
 }
 
 
@@ -7322,30 +7157,32 @@ 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);
+             }
+         }
+      }
 }
 
 
@@ -7372,7 +7209,8 @@ next_instrs_are_b_retw (fragS *fragP)
     return FALSE;
 
   /* Check for the conditional branch.  */
-  xtensa_insnbuf_from_chars (isa, insnbuf, &next_fragP->fr_literal[offset], 0);
+  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;
@@ -7400,7 +7238,8 @@ next_instrs_are_b_retw (fragS *fragP)
     return FALSE;
 
   /* Check for the retw/retw.n.  */
-  xtensa_insnbuf_from_chars (isa, insnbuf, &next_fragP->fr_literal[offset], 0);
+  xtensa_insnbuf_from_chars
+    (isa, insnbuf, (unsigned char *) &next_fragP->fr_literal[offset], 0);
   fmt = xtensa_format_decode (isa, insnbuf);
 
   /* Because RETW[.N] is not bundleable, a VLIW bundle here means that we
@@ -7430,30 +7269,32 @@ 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);
+             }
+         }
+      }
 }
 
 
@@ -7487,103 +7328,86 @@ next_instr_is_loop_end (fragS *fragP)
    make it at least 12 bytes away.  In any case close it off with a
    .fill 0.  */
 
-static size_t min_bytes_to_other_loop_end (fragS *, fragS *, offsetT, size_t);
+static offsetT min_bytes_to_other_loop_end
+  (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)
-           {
-             size_t min_bytes;
-             size_t 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"),
-                                     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);
+             }
+           assert (fragP->fr_type != rs_machine_dependent
+                   || fragP->fr_subtype != RELAX_ADD_NOP_IF_CLOSE_LOOP_END);
+         }
+      }
 }
 
 
-static size_t unrelaxed_frag_min_size (fragS *);
+static offsetT unrelaxed_frag_min_size (fragS *);
 
-static size_t
+static offsetT
 min_bytes_to_other_loop_end (fragS *fragP,
                             fragS *current_target,
-                            offsetT current_offset,
-                            size_t max_size)
+                            offsetT max_size)
 {
-  size_t offset = 0;
+  offsetT offset = 0;
   fragS *current_fragP;
 
   for (current_fragP = fragP;
@@ -7592,23 +7416,23 @@ 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;
 }
 
 
-static size_t
+static offsetT
 unrelaxed_frag_min_size (fragS *fragP)
 {
-  size_t size = fragP->fr_fix;
+  offsetT size = fragP->fr_fix;
 
-  /* add fill size */
+  /* Add fill size.  */
   if (fragP->fr_type == rs_fill)
     size += fragP->fr_offset;
 
@@ -7616,14 +7440,14 @@ unrelaxed_frag_min_size (fragS *fragP)
 }
 
 
-static size_t
+static offsetT
 unrelaxed_frag_max_size (fragS *fragP)
 {
-  size_t size = fragP->fr_fix;
+  offsetT size = fragP->fr_fix;
   switch (fragP->fr_type)
     {
     case 0:
-      /* Empty frags created by the obstack allocation scheme 
+      /* Empty frags created by the obstack allocation scheme
         end up with type 0.  */
       break;
     case rs_fill:
@@ -7669,83 +7493,70 @@ 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 size_t count_insns_to_loop_end (fragS *, bfd_boolean, size_t);
+static int count_insns_to_loop_end (fragS *, bfd_boolean, int);
 static bfd_boolean 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;
+       fragS *current_target = NULL;
+       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_target = symbol_get_frag (fragP->fr_symbol);
+               current_opcode = t_insn.opcode;
+               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)
-           {
-             size_t insn_count =
-               count_insns_to_loop_end (fragP->fr_next, TRUE, 3);
-             if (insn_count < 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);
+             }
+         }
+      }
 }
 
 
-static size_t unrelaxed_frag_min_insn_count (fragS *);
+static int unrelaxed_frag_min_insn_count (fragS *);
 
-static size_t
+static int
 count_insns_to_loop_end (fragS *base_fragP,
                         bfd_boolean count_relax_add,
-                        size_t max_count)
+                        int max_count)
 {
   fragS *fragP = NULL;
-  size_t insn_count = 0;
+  int insn_count = 0;
 
   fragP = base_fragP;
 
@@ -7773,12 +7584,12 @@ count_insns_to_loop_end (fragS *base_fragP,
 }
 
 
-static size_t
+static int
 unrelaxed_frag_min_insn_count (fragS *fragP)
 {
   xtensa_isa isa = xtensa_default_isa;
   static xtensa_insnbuf insnbuf = NULL;
-  size_t insn_count = 0;
+  int insn_count = 0;
   int offset = 0;
 
   if (!fragP->tc_frag_data.is_insn)
@@ -7792,7 +7603,8 @@ unrelaxed_frag_min_insn_count (fragS *fragP)
     {
       xtensa_format fmt;
 
-      xtensa_insnbuf_from_chars (isa, insnbuf, fragP->fr_literal + offset, 0);
+      xtensa_insnbuf_from_chars
+       (isa, insnbuf, (unsigned char *) fragP->fr_literal + offset, 0);
       fmt = xtensa_format_decode (isa, insnbuf);
 
       if (fmt == XTENSA_UNDEFINED)
@@ -7845,7 +7657,8 @@ unrelaxed_frag_has_b_j (fragS *fragP)
       xtensa_format fmt;
       int slot;
 
-      xtensa_insnbuf_from_chars (isa, insnbuf, fragP->fr_literal + offset, 0);
+      xtensa_insnbuf_from_chars
+       (isa, insnbuf, (unsigned char *) fragP->fr_literal + offset, 0);
       fmt = xtensa_format_decode (isa, insnbuf);
       if (fmt == XTENSA_UNDEFINED)
        return FALSE;
@@ -7873,51 +7686,52 @@ static void
 xtensa_sanity_check (void)
 {
   char *file_name;
-  int line;
-
+  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);
+  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);
 }
 
@@ -7983,7 +7797,7 @@ is_local_forward_loop (const TInsn *insn, fragS *fragP)
   if (insn->insn_type != ITYPE_INSN)
     return FALSE;
 
-  if (xtensa_opcode_is_loop (xtensa_default_isa, insn->opcode) == 0)
+  if (xtensa_opcode_is_loop (xtensa_default_isa, insn->opcode) != 1)
     return FALSE;
 
   if (insn->ntok <= LOOP_IMMED_OPN)
@@ -8015,24 +7829,69 @@ is_local_forward_loop (const TInsn *insn, fragS *fragP)
   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 (stdoutput, info_sec, SEC_HAS_CONTENTS | SEC_READONLY);
+
+  data = xmalloc (100);
+  sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n",
+          XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI);
+  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
 /* Alignment Functions.  */
 
-static size_t
-get_text_align_power (int target_size)
+static int
+get_text_align_power (unsigned target_size)
 {
-  size_t i = 0;
-  for (i = 0; i < sizeof (size_t); i++)
-    {
-      if (target_size <= (1 << i))
-       return i;
-    }
-  assert (0);
-  return 0;
+  if (target_size <= 4)
+    return 2;
+  assert (target_size == 8);
+  return 3;
 }
 
 
-static addressT
+static int
 get_text_align_max_fill_size (int align_pow,
                              bfd_boolean use_nops,
                              bfd_boolean use_no_density)
@@ -8046,118 +7905,86 @@ get_text_align_max_fill_size (int align_pow,
 }
 
 
-/* get_text_align_fill_size ()
-
-   Desired alignments:
-      give the address
-      target_size = size of next instruction
-      align_pow = get_text_align_power (target_size).
-      use_nops = 0
-      use_no_density = 0;
-   Loop alignments:
-      address = current address + loop instruction size;
-      target_size = 3 (for 2 or 3 byte target)
-                  = 4 (for 4 byte target)
-                  = 8 (for 8 byte target)
-      align_pow = get_text_align_power (target_size);
-      use_nops = 1
-      use_no_density = set appropriately
-   Text alignments:
-      address = current address + loop instruction size;
-      target_size = 0
-      align_pow = get_text_align_power (target_size);
-      use_nops = 0
-      use_no_density = 0.  */
+/* Calculate the minimum bytes of fill needed at "address" to align a
+   target instruction of size "target_size" so that it does not cross a
+   power-of-two boundary specified by "align_pow".  If "use_nops" is FALSE,
+   the fill can be an arbitrary number of bytes.  Otherwise, the space must
+   be filled by NOP instructions.  */
 
-static addressT
+static int
 get_text_align_fill_size (addressT address,
                          int align_pow,
                          int target_size,
                          bfd_boolean use_nops,
                          bfd_boolean use_no_density)
 {
-  /* Input arguments:
-
-     align_pow: log2 (required alignment).
-
-     target_size: alignment must allow the new_address and
-     new_address+target_size-1.
-
-     use_nops: if TRUE, then we can only use 2- or 3-byte nops.
-
-     use_no_density: if use_nops and use_no_density, we can only use
-     3-byte nops.
-
-     Usually the align_pow is the power of 2 that is greater than 
-     or equal to the target_size.  This handles the 2-byte, 3-byte 
-     and 8-byte instructions.
+  addressT alignment, fill, fill_limit, fill_step;
+  bfd_boolean skip_one = FALSE;
 
-     Two cases:
+  alignment = (1 << align_pow);
+  assert (target_size > 0 && alignment >= (addressT) target_size);
 
-     (1) aligning an instruction properly, but without using NOPs.
-       E.G.: a 3-byte instruction can go on any address where address mod 4
-       is zero or one.  The aligner uses this case to find the optimal
-       number of fill bytes for relax_frag_for_align.
-
-     (2) aligning an instruction properly, but where we might need to use
-       extra NOPs.  E.G.: when the aligner couldn't find enough widenings
-       or similar to get the optimal location.  */
-
-  size_t alignment = (1 << align_pow);
-
-  assert (target_size != 0);
-  
   if (!use_nops)
     {
-      unsigned fill_bytes;
-      for (fill_bytes = 0; fill_bytes < alignment; fill_bytes++)
-       {
-         addressT end_address = address + target_size - 1 + fill_bytes;
-         addressT start_address = address + fill_bytes;
-         if ((end_address >> align_pow) == (start_address >> align_pow))
-           return fill_bytes;
-       }
-      assert (0);
+      fill_limit = alignment;
+      fill_step = 1;
     }
-
-  /* This is the slightly harder case.  */
-  assert ((int) alignment >= target_size);
-  assert (target_size > 0);
-  if (!use_no_density)
+  else if (!use_no_density)
     {
-      size_t i;
-      for (i = 0; i < alignment * 2; i++)
-       {
-         if (i == 1)
-           continue;
-         if ((address + i) >> align_pow
-             == (address + i + target_size - 1) >> align_pow)
-           return i;
-       }
+      /* Combine 2- and 3-byte NOPs to fill anything larger than one.  */
+      fill_limit = alignment * 2;
+      fill_step = 1;
+      skip_one = TRUE;
     }
   else
     {
-      size_t i;
+      /* Fill with 3-byte NOPs -- can only fill multiples of 3.  */
+      fill_limit = alignment * 3;
+      fill_step = 3;
+    }
 
-      /* Can only fill multiples of 3.  */
-      for (i = 0; i <= alignment * 3; i += 3)
-       {
-         if ((address + i) >> align_pow
-             == (address + i + target_size - 1) >> align_pow)
-           return i;
-       }
+  /* Try all fill sizes until finding one that works.  */
+  for (fill = 0; fill < fill_limit; fill += fill_step)
+    {
+      if (skip_one && fill == 1)
+       continue;
+      if ((address + fill) >> align_pow
+         == (address + fill + target_size - 1) >> align_pow)
+       return fill;
     }
   assert (0);
   return 0;
 }
 
 
+static int
+branch_align_power (segT sec)
+{
+  /* If the Xtensa processor has a fetch width of 8 bytes, and the section
+     is aligned to at least an 8-byte boundary, then a branch target need
+     only fit within an 8-byte aligned block of memory to avoid a stall.
+     Otherwise, try to fit branch targets within 4-byte aligned blocks
+     (which may be insufficient, e.g., if the section has no alignment, but
+     it's good enough).  */
+  if (xtensa_fetch_width == 8)
+    {
+      if (get_recorded_alignment (sec) >= 3)
+       return 3;
+    }
+  else
+    assert (xtensa_fetch_width == 4);
+
+  return 2;
+}
+
+
 /* This will assert if it is not possible.  */
 
-static size_t
-get_text_align_nop_count (size_t fill_size, bfd_boolean use_no_density)
+static int
+get_text_align_nop_count (offsetT fill_size, bfd_boolean use_no_density)
 {
-  size_t count = 0;
+  int count = 0;
+
   if (use_no_density)
     {
       assert (fill_size % 3 == 0);
@@ -8168,7 +7995,7 @@ get_text_align_nop_count (size_t fill_size, bfd_boolean use_no_density)
 
   while (fill_size > 1)
     {
-      size_t insn_size = 3;
+      int insn_size = 3;
       if (fill_size == 2 || fill_size == 4)
        insn_size = 2;
       fill_size -= insn_size;
@@ -8179,21 +8006,21 @@ get_text_align_nop_count (size_t fill_size, bfd_boolean use_no_density)
 }
 
 
-static size_t
-get_text_align_nth_nop_size (size_t fill_size,
-                            size_t n,
+static int
+get_text_align_nth_nop_size (offsetT fill_size,
+                            int n,
                             bfd_boolean use_no_density)
 {
-  size_t count = 0;
-
-  assert (get_text_align_nop_count (fill_size, use_no_density) > n);
+  int count = 0;
 
   if (use_no_density)
     return 3;
 
+  assert (fill_size != 1);     /* Bad argument.  */
+
   while (fill_size > 1)
     {
-      size_t insn_size = 3;
+      int insn_size = 3;
       if (fill_size == 2 || fill_size == 4)
        insn_size = 2;
       fill_size -= insn_size;
@@ -8216,21 +8043,21 @@ get_noop_aligned_address (fragS *fragP, addressT address)
      the smallest number of bytes that need to be added to
      ensure that the next fragment's FIRST instruction will fit
      in a single word.
-     
+
      E.G.,   2 bytes : 0, 1, 2 mod 4
             3 bytes: 0, 1 mod 4
-     
+
      If the FIRST instruction MIGHT be relaxed,
      assume that it will become a 3-byte instruction.
-     
+
      Note again here that LOOP instructions are not bundleable,
      and this relaxation only applies to LOOP opcodes.  */
-  
-  size_t fill_size = 0;
+
+  int fill_size = 0;
   int first_insn_size;
   int loop_insn_size;
   addressT pre_opcode_bytes;
-  size_t alignment;
+  int align_power;
   fragS *first_insn;
   xtensa_opcode opcode;
   bfd_boolean is_loop;
@@ -8254,25 +8081,17 @@ 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.  */
-  alignment = get_text_align_power (first_insn_size);
+  align_power = get_text_align_power (first_insn_size);
+  record_alignment (now_seg, align_power);
 
-  /* Is now_seg valid?  */
-  record_alignment (now_seg, alignment);
-  
   fill_size = get_text_align_fill_size
-    (address + pre_opcode_bytes,
-     get_text_align_power (first_insn_size),
-     first_insn_size, TRUE, fragP->tc_frag_data.is_no_density);
+    (address + pre_opcode_bytes, align_power, first_insn_size, TRUE,
+     fragP->tc_frag_data.is_no_density);
 
   return address + fill_size;
 }
@@ -8295,15 +8114,16 @@ get_noop_aligned_address (fragS *fragP, addressT address)
               >=5 : 3-byte instruction + fn (n-3)
    widening - widen previous instructions.  */
 
-static addressT
-get_aligned_diff (fragS *fragP, addressT address, addressT *max_diff)
+static offsetT
+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;
-  int text_align_power;
-  addressT opt_diff;
+  int align_power;
+  offsetT opt_diff;
+  offsetT branch_align;
 
   assert (fragP->fr_type == rs_machine_dependent);
   switch (fragP->fr_subtype)
@@ -8312,17 +8132,21 @@ get_aligned_diff (fragS *fragP, addressT address, addressT *max_diff)
       target_size = next_frag_format_size (fragP);
       if (target_size == XTENSA_UNDEFINED)
        target_size = 3;
-      text_align_power = get_text_align_power (xtensa_fetch_width);
-      opt_diff = get_text_align_fill_size (address, text_align_power,
+      align_power = branch_align_power (now_seg);
+      branch_align = 1 << align_power;
+      /* Don't count on the section alignment being as large as the target.  */
+      if (target_size > branch_align)
+       target_size = branch_align;
+      opt_diff = get_text_align_fill_size (address, align_power,
                                           target_size, FALSE, FALSE);
 
-      *max_diff = opt_diff + xtensa_fetch_width
-       - (target_size + ((address + opt_diff) % xtensa_fetch_width));
+      *max_diff = (opt_diff + branch_align
+                  - (target_size + ((address + opt_diff) % branch_align)));
       assert (*max_diff >= opt_diff);
       return opt_diff;
 
     case RELAX_ALIGN_NEXT_OPCODE:
-      target_size = next_frag_format_size (fragP);
+      target_size = get_loop_align_size (next_frag_format_size (fragP));
       loop_insn_offset = 0;
       is_loop = next_frag_opcode_is_loop (fragP, &loop_opcode);
       assert (is_loop);
@@ -8333,17 +8157,14 @@ get_aligned_diff (fragS *fragP, addressT address, addressT *max_diff)
          != 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);
-      text_align_power = get_text_align_power (target_size),
-      opt_diff = get_text_align_fill_size (target_address, text_align_power,
+      align_power = get_text_align_power (target_size),
+      opt_diff = get_text_align_fill_size (target_address, align_power,
                                           target_size, FALSE, FALSE);
 
       *max_diff = xtensa_fetch_width
@@ -8378,7 +8199,8 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
   int unreported = fragP->tc_frag_data.unreported_expansion;
   long new_stretch = 0;
   char *file_name;
-  int line, lit_size;
+  unsigned line;
+  int lit_size;
   static xtensa_insnbuf vbuf = NULL;
   int slot, num_slots;
   xtensa_format fmt;
@@ -8429,7 +8251,8 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
       if (vbuf == NULL)
        vbuf = xtensa_insnbuf_alloc (isa);
 
-      xtensa_insnbuf_from_chars (isa, vbuf, fragP->fr_opcode, 0);
+      xtensa_insnbuf_from_chars
+       (isa, vbuf, (unsigned char *) fragP->fr_opcode, 0);
       fmt = xtensa_format_decode (isa, vbuf);
       num_slots = xtensa_format_num_slots (isa, fmt);
 
@@ -8477,7 +8300,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) 
+  if (! fragP->tc_frag_data.relax_seen)
     {
       fragP->tc_frag_data.relax_seen = TRUE;
       *stretched_p = 1;
@@ -8531,7 +8354,7 @@ relax_frag_add_nop (fragS *fragP)
 
   if (fragP->fr_var < length)
     {
-      as_fatal (_("fr_var (%ld) < length (%d)"), fragP->fr_var, length);
+      as_fatal (_("fr_var (%ld) < length (%d)"), (long) fragP->fr_var, length);
       return 0;
     }
 
@@ -8612,7 +8435,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;
@@ -8641,8 +8464,7 @@ find_address_of_next_align_frag (fragS **fragPP,
                  (*widens)++;
                  break;
                }
-             /* FIXME: shouldn't this add the expansion of all slots?  */
-             address += fragP->tc_frag_data.text_expansion[0];
+             address += total_frag_text_expansion (fragP);;
              break;
 
            case RELAX_IMMED:
@@ -8665,7 +8487,7 @@ find_address_of_next_align_frag (fragS **fragPP,
              return 0;
            }
        }
-      else 
+      else
        {
          /* Just punt if we don't know the type.  */
          *fragPP = fragP;
@@ -8681,11 +8503,6 @@ find_address_of_next_align_frag (fragS **fragPP,
 
 static long bytes_to_stretch (fragS *, int, int, int, int);
 
-/* Undefine LOOKAHEAD_ALIGNER to get the older behavior.
-   I'll leave this in until I am more confident this works.  */
-
-#define LOOKAHEAD_ALIGNER 1
-
 static long
 future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
 {
@@ -8705,34 +8522,41 @@ 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);
-      if (max_diff == 0) 
+      if (max_diff == 0)
        return 0;
-#ifdef LOOKAHEAD_ALIGNER
+
       if (fragP)
        fragP = fragP->fr_next;
 
       while (fragP && opt_diff < max_diff && address)
        {
          /* We only use these to determine if we can exit early
-            because there will be plenty of ways to align future 
+            because there will be plenty of ways to align future
             align frags.  */
-         unsigned int glob_widens = 0;
+         int glob_widens = 0;
          int dnn = 0;
          int dw = 0;
          bfd_boolean 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 >= xtensa_fetch_width))
-           break;
+         if (glob_pad || glob_widens >= (1 << branch_align_power (now_seg)))
+           address = 0;
 
-         if (address) 
+         if (address)
            {
              offsetT next_m_diff;
              offsetT next_o_diff;
@@ -8762,7 +8586,7 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
              fragP = fragP->fr_next;
            }
        }
-#endif /* LOOKAHEAD_ALIGNER */
+
       /* If there are enough wideners in between, do it.  */
       if (paddable)
        {
@@ -8773,24 +8597,21 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
            }
          return 0;
        }
-      local_stretch_amount 
+      local_stretch_amount
        = bytes_to_stretch (this_frag, wide_nops, narrow_nops,
                            num_widens, local_opt_diff);
-#ifdef LOOKAHEAD_ALIGNER
-      global_stretch_amount 
-       = bytes_to_stretch (this_frag, wide_nops, narrow_nops, 
+      global_stretch_amount
+       = bytes_to_stretch (this_frag, wide_nops, narrow_nops,
                            num_widens, opt_diff);
-      /* If the condition below is true, then the frag couldn't 
-        stretch the correct amount for the global case, so we just 
-        optimize locally.  We'll rely on the subsequent frags to get 
+      /* If the condition below is true, then the frag couldn't
+        stretch the correct amount for the global case, so we just
+        optimize locally.  We'll rely on the subsequent frags to get
         the correct alignment in the global case.  */
       if (global_stretch_amount < local_stretch_amount)
        stretch_amount = local_stretch_amount;
       else
        stretch_amount = global_stretch_amount;
-#else /* ! LOOKAHEAD_ALIGNER */
-      stretch_amount = local_stretch_amount;
-#endif /* ! LOOKAHEAD_ALIGNER */
+
       if (this_frag->fr_subtype == RELAX_SLOTS
          && this_frag->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
        assert (stretch_amount <= 1);
@@ -8831,7 +8652,7 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
     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)
+    c          0      1         4 (case 6b makes this case unnecessary)
     d          1      1         1 (case 6a makes this case unnecessary)
     e          0      2         2 (case 6a makes this case unnecessary)
     f          0      3         0 (case 6a makes this case unnecessary)
@@ -8856,7 +8677,7 @@ bytes_to_stretch (fragS *this_frag,
   assert (desired_diff >= 0 && desired_diff < 8);
   if (desired_diff == 0)
     return 0;
-  
+
   assert (wide_nops > 0 || num_widens > 0);
 
   /* Always prefer widening to NOP-filling.  */
@@ -8866,7 +8687,7 @@ bytes_to_stretch (fragS *this_frag,
         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
@@ -8876,7 +8697,7 @@ bytes_to_stretch (fragS *this_frag,
       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.  */
@@ -8890,7 +8711,7 @@ bytes_to_stretch (fragS *this_frag,
          if (!this_frag->tc_frag_data.is_no_density && narrow_nops == 1)
            return 2; /* case 2 */
          return 0;
-       case 3: 
+       case 3:
          if (wide_nops > 1)
            return 0;
          else
@@ -8904,7 +8725,7 @@ bytes_to_stretch (fragS *this_frag,
        case 5:
          if (num_widens >= 2 && wide_nops == 1)
            return 3; /* case 5a */
-         /* We will need two nops.  Are there enough nops 
+         /* We will need two nops.  Are there enough nops
             between here and the align target?  */
          if (wide_nops < 2 || narrow_nops == 0)
            return 0;
@@ -8936,10 +8757,10 @@ bytes_to_stretch (fragS *this_frag,
     }
   else
     {
-      /* We will need a NOP no matter what, but should we widen 
+      /* We will need a NOP no matter what, but should we widen
         this instruction to help?
 
-        This is a RELAX_FRAG_NARROW frag.  */
+        This is a RELAX_NARROW frag.  */
       switch (desired_diff)
        {
        case 1:
@@ -8989,7 +8810,6 @@ relax_frag_immed (segT segP,
                  bfd_boolean estimate_only)
 {
   TInsn tinsn;
-  vliw_insn orig_vinsn;
   int old_size;
   bfd_boolean negatable_branch = FALSE;
   bfd_boolean branch_jmp_to_next = FALSE;
@@ -9004,15 +8824,15 @@ relax_frag_immed (segT segP,
 
   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)
+  xg_clear_vinsn (&cur_vinsn);
+  vinsn_from_chars (&cur_vinsn, fragP->fr_opcode);
+  if (cur_vinsn.num_slots > 1)
     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)
@@ -9102,13 +8922,8 @@ relax_frag_immed (segT segP,
        }
     }
 
-  /* FIXME: When a negatable branch expands and then contracts in a
-     subsequent pass, update_next_frag_state correctly updates the
-     type of the frag to RELAX_MAYBE_UNREACHABLE, but it doesn't undo
-     any expansion relax_frag_for_align may have expected it to.  For
-     now, change back to only call it when the branch expands.  */
   if (negatable_branch && istack.ninsn > 1)
-    update_next_frag_state (fragP, FALSE /* istack.ninsn > 1 */);      
+    update_next_frag_state (fragP);
 
   return this_text_diff;
 }
@@ -9130,7 +8945,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp)
   int num_slots;
   xtensa_format fmt;
   char *file_name;
-  int line;
+  unsigned line;
 
   as_where (&file_name, &line);
   new_logical_line (fragp->fr_file, fragp->fr_line);
@@ -9154,7 +8969,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp)
       if (vbuf == NULL)
        vbuf = xtensa_insnbuf_alloc (isa);
 
-      xtensa_insnbuf_from_chars (isa, vbuf, fragp->fr_opcode, 0);
+      xtensa_insnbuf_from_chars
+       (isa, vbuf, (unsigned char *) fragp->fr_opcode, 0);
       fmt = xtensa_format_decode (isa, vbuf);
       num_slots = xtensa_format_num_slots (isa, fmt);
 
@@ -9239,11 +9055,10 @@ static void
 convert_frag_align_next_opcode (fragS *fragp)
 {
   char *nop_buf;               /* Location for Writing.  */
-  size_t i;
-
   bfd_boolean use_no_density = fragp->tc_frag_data.is_no_density;
   addressT aligned_address;
-  size_t fill_size, nop_count;
+  offsetT fill_size;
+  int nop, nop_count;
 
   aligned_address = get_noop_aligned_address (fragp, fragp->fr_address +
                                              fragp->fr_fix);
@@ -9251,10 +9066,10 @@ convert_frag_align_next_opcode (fragS *fragp)
   nop_count = get_text_align_nop_count (fill_size, use_no_density);
   nop_buf = fragp->fr_literal + fragp->fr_fix;
 
-  for (i = 0; i < nop_count; i++)
+  for (nop = 0; nop < nop_count; nop++)
     {
-      size_t nop_size;
-      nop_size = get_text_align_nth_nop_size (fill_size, i, use_no_density);
+      int nop_size;
+      nop_size = get_text_align_nth_nop_size (fill_size, nop, use_no_density);
 
       assemble_nop (nop_size, nop_buf);
       nop_buf += nop_size;
@@ -9269,14 +9084,13 @@ 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, error_val;
+  int size, old_size, diff;
   offsetT frag_offset;
 
   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
              || fragP->tc_frag_data.text_expansion[0] == 0);
@@ -9305,18 +9119,15 @@ convert_frag_narrow (segT segP, fragS *fragP, xtensa_format fmt, int slot)
   tinsn_init (&single_target);
   frag_offset = fragP->fr_opcode - fragP->fr_literal;
 
-  error_val = xg_expand_narrow (&single_target, &tinsn);
-  if (error_val)
+  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);
@@ -9367,7 +9178,6 @@ convert_frag_immed (segT segP,
   bfd_boolean expanded = FALSE;
   bfd_boolean 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;
   int bytes;
@@ -9375,13 +9185,13 @@ convert_frag_immed (segT segP,
 
   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)
+  vinsn_from_chars (&cur_vinsn, fr_opcode);
+  if (cur_vinsn.num_slots > 1)
     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;
@@ -9395,22 +9205,23 @@ 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);
+         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);
-      xtensa_insnbuf_to_chars (isa, orig_vinsn.insnbuf, fr_opcode, 0);
+      vinsn_to_insnbuf (&cur_vinsn, fr_opcode, frag_now, TRUE);
+      xtensa_insnbuf_to_chars
+       (isa, cur_vinsn.insnbuf, (unsigned char *) fr_opcode, 0);
       fragP->fr_var = 0;
     }
-  else if (!orig_tinsn.is_specific_opcode)
+  else
     {
       /* Here is the fun stuff:  Get the immediate field from this
         instruction.  If it fits, we're done.  If not, find the next
@@ -9521,10 +9332,7 @@ convert_frag_immed (segT segP,
              /* 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;
+             reloc_type = map_operator_to_reloc (tinsn->tok[0].X_op);
              fix_new_exp_in_seg (target_seg, 0, lit_frag, 0, 4,
                                  &tinsn->tok[0], FALSE, reloc_type);
              break;
@@ -9540,68 +9348,32 @@ convert_frag_immed (segT segP,
                  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,
-                                          immed_instr, 0);
+                 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;
                  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,
+                       (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,
+                 xg_emit_insn_to_buf (tinsn, immed_instr, fragP,
                                       immed_instr - fragP->fr_literal, TRUE);
-#if 0
-                 /* Code to recognize branch-around expansion
-                    so the fragment is properly marked as ending in a
-                    jump. */
-                 if ((((i == istack.ninsn - 2)
-                       && (istack.insn[istack.ninsn-1].insn_type
-                           == ITYPE_LABEL))
-                      || i == istack.ninsn -1)
-                     && xtensa_opcode_is_jump (xtensa_default_isa,
-                                               tinsn->opcode) == 1
-                     && fragP->fr_next != NULL
-                     && ! fragP->fr_next->tc_frag_data.is_unreachable)
-                   {
-                     /* Create a new unreachable frag of zero size.  */
-                     size_t frag_size = sizeof (fragS);
-                     fragS *new_fragP = (fragS *) xmalloc (frag_size);
-                     memset (new_fragP, 0, frag_size);
-                     new_fragP->fr_address = fragP->fr_next->fr_address;
-                     new_fragP->fr_next = fragP->fr_next;
-                     new_fragP->fr_fix = 0;
-                     new_fragP->fr_var = 0;
-                     new_fragP->fr_type = rs_fill;
-                     new_fragP->tc_frag_data.is_unreachable = TRUE;
-                     /* The rest are zeros....  */
-                     /* Link it in to the chain.  */
-                     fragP->fr_next = new_fragP;
-                   }
-#endif
                }
              immed_instr += size;
              total_size += size;
@@ -9618,9 +9390,6 @@ convert_frag_immed (segT segP,
       fragP->fr_fix += diff;
     }
 
-  /* Clean it up.  */
-  xg_free_vinsn (&orig_vinsn);
-
   /* Check for undefined immediates in LOOP instructions.  */
   if (is_loop)
     {
@@ -9709,7 +9478,7 @@ convert_frag_immed_finish_loop (segT segP, fragS *fragP, TInsn *tinsn)
   addressT addi_offset = 9;
   addressT addmi_offset = 12;
   fragS *next_fragP;
-  size_t target_count;
+  int target_count;
 
   if (!insnbuf)
     insnbuf = xtensa_insnbuf_alloc (isa);
@@ -9744,11 +9513,6 @@ convert_frag_immed_finish_loop (segT segP, fragS *fragP, TInsn *tinsn)
       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;
@@ -9774,11 +9538,13 @@ convert_frag_immed_finish_loop (segT segP, fragS *fragP, TInsn *tinsn)
   tinsn_to_insnbuf (&addi_insn, insnbuf);
 
   fragP->tc_frag_data.is_insn = TRUE;
-  xtensa_insnbuf_to_chars (isa, insnbuf, fragP->fr_opcode + addi_offset, 0);
+  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, fragP->fr_opcode + addmi_offset, 0);
+  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
@@ -9910,38 +9676,6 @@ set_subseg_freq (segT seg, subsegT subseg, float total_f, float target_f)
 \f
 /* Segment Lists and emit_state Stuff.  */
 
-/* Remove the segment from the global sections list.  */
-
-static void
-xtensa_remove_section (segT sec)
-{
-  /* Handle brain-dead bfd_section_list_remove macro, which
-     expect the address of the prior section's "next" field, not
-     just the address of the section to remove.  */
-
-  segT *ps_next_ptr = &stdoutput->sections;
-  while (*ps_next_ptr != sec && *ps_next_ptr != NULL) 
-    ps_next_ptr = &(*ps_next_ptr)->next;
-  
-  assert (*ps_next_ptr != NULL);
-
-  bfd_section_list_remove (stdoutput, ps_next_ptr);
-}
-
-
-static void
-xtensa_insert_section (segT after_sec, segT sec)
-{
-  segT *after_sec_next;
-  if (after_sec == NULL)
-    after_sec_next = &stdoutput->sections;
-  else
-    after_sec_next = &after_sec->next;
-
-  bfd_section_list_insert (stdoutput, after_sec_next, sec);
-}
-
-
 static void
 xtensa_move_seg_list_to_beginning (seg_list *head)
 {
@@ -9952,9 +9686,11 @@ xtensa_move_seg_list_to_beginning (seg_list *head)
 
       /* Move the literal section to the front of the section list.  */
       assert (literal_section);
-      xtensa_remove_section (literal_section);
-      xtensa_insert_section (NULL, literal_section);
-
+      if (literal_section != stdoutput->sections)
+       {
+         bfd_section_list_remove (stdoutput, literal_section);
+         bfd_section_list_prepend (stdoutput, literal_section);
+       }
       head = head->next;
     }
 }
@@ -9975,15 +9711,17 @@ xtensa_move_literals (void)
   sym_list *lit;
 
   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)
+  for (segment = literal_head->next; segment; segment = segment->next)
     {
+      /* Keep the literals for .init and .fini in separate sections.  */
+      if (!strcmp (segment_name (segment->seg), INIT_SECTION_NAME)
+         || !strcmp (segment_name (segment->seg), FINI_SECTION_NAME))
+       continue;
+
       frchain_from = seg_info (segment->seg)->frchainP;
       search_frag = frchain_from->frch_root;
       literal_pool = NULL;
@@ -10021,17 +9759,15 @@ xtensa_move_literals (void)
            {
              literal_pool = search_frag->tc_frag_data.literal_frag;
              assert (literal_pool->fr_subtype == RELAX_LITERAL_POOL_BEGIN);
-             /* Note that we set this fr_var to be a fix
-                chain when we created the literal pool location
-                as RELAX_LITERAL_POOL_BEGIN.  */
-             frchain_to = (frchainS *) literal_pool->fr_var;
+             frchain_to = literal_pool->tc_frag_data.lit_frchain;
+             assert (frchain_to);
            }
          insert_after = literal_pool;
 
          while (insert_after->fr_next->fr_subtype != RELAX_LITERAL_POOL_END)
            insert_after = insert_after->fr_next;
 
-         dest_seg = (segT) insert_after->fr_next->fr_var;
+         dest_seg = insert_after->fr_next->tc_frag_data.lit_seg;
 
          *frag_splice = next_frag;
          search_frag->fr_next = insert_after->fr_next;
@@ -10069,7 +9805,6 @@ xtensa_move_literals (void)
        }
       frchain_from->fix_tail = NULL;
       xtensa_restore_emit_state (&state);
-      segment = segment->next;
     }
 
   /* Now fix up the SEGMENT value for all the literal symbols.  */
@@ -10097,7 +9832,7 @@ mark_literal_frags (seg_list *segment)
     {
       frchain_from = seg_info (segment->seg)->frchainP;
       search_frag = frchain_from->frch_root;
-      while (search_frag) 
+      while (search_frag)
        {
          search_frag->tc_frag_data.is_literal = TRUE;
          search_frag = search_frag->fr_next;
@@ -10122,8 +9857,8 @@ xtensa_reorder_seg_list (seg_list *head, segT after)
       assert (literal_section);
       if (literal_section != after)
        {
-         xtensa_remove_section (literal_section);
-         xtensa_insert_section (after, literal_section);
+         bfd_section_list_remove (stdoutput, literal_section);
+         bfd_section_list_insert_after (stdoutput, after, literal_section);
        }
 
       head = head->next;
@@ -10150,8 +9885,6 @@ 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)
@@ -10169,10 +9902,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);
@@ -10186,18 +9917,12 @@ 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 = 
+  segT lit_seg;
+  bfd_boolean is_init =
     (now_seg && !strcmp (segment_name (now_seg), INIT_SECTION_NAME));
-
-  bfd_boolean is_fini = 
+  bfd_boolean is_fini =
     (now_seg && !strcmp (segment_name (now_seg), FINI_SECTION_NAME));
 
   if (pool_location == NULL
@@ -10206,39 +9931,20 @@ xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
       && !is_init && ! is_fini)
     {
       as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
+
+      /* When we mark a literal pool location, we want to put a frag in
+        the literal pool that points to it.  But to do that, we want to
+        switch_to_literal_fragment.  But literal sections don't have
+        literal pools, so their location is always null, so we would
+        recurse forever.  This is kind of hacky, but it works.  */
+
       recursive = TRUE;
       xtensa_mark_literal_pool_location ();
       recursive = FALSE;
     }
 
-  /* 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
-    {
-      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);
-    }
+  lit_seg = cache_literal_section (FALSE);
+  xtensa_switch_section_emit_state (result, lit_seg, 0);
 
   if (!use_literal_section
       && !is_init && !is_fini
@@ -10268,7 +9974,7 @@ xtensa_switch_section_emit_state (emit_state *state,
   state->now_subseg = now_subseg;
   state->generating_literals = generating_literals;
   generating_literals++;
-  subseg_new (segment_name (new_now_seg), new_now_subseg);
+  subseg_set (new_now_seg, new_now_subseg);
 }
 
 
@@ -10278,53 +9984,133 @@ static void
 xtensa_restore_emit_state (emit_state *state)
 {
   generating_literals = state->generating_literals;
-  subseg_new (state->name, state->now_subseg);
+  subseg_set (state->now_seg, state->now_subseg);
 }
 
 
-/* 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 bfd_boolean
+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 (bfd_boolean use_abs_literals)
+{
+  const char *text_name, *group_name = 0;
+  char *base_name, *name, *suffix;
+  segT *pcached;
+  segT seg, current_section;
+  int current_subsec;
+  bfd_boolean 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;
+    }
+
+  /* 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 = xmalloc (strlen (base_name) + strlen (group_name) + 2);
+      sprintf (name, "%s.%s", base_name, group_name);
+    }
+  else if (strncmp (text_name, ".gnu.linkonce.", linkonce_len) == 0)
+    {
+      suffix = strchr (text_name + linkonce_len, '.');
+
+      name = xmalloc (linkonce_len + strlen (base_name) + 1
+                     + (suffix ? strlen (suffix) : 0));
+      strcpy (name, ".gnu.linkonce");
+      strcat (name, base_name);
+      if (suffix)
+       strcat (name, suffix);
+      linkonce = TRUE;
+    }
+  else
+    {
+      /* If the section name ends with ".text", then replace that suffix
+        instead of appending an additional suffix.  */
+      size_t len = strlen (text_name);
+      if (len >= 5 && strcmp (text_name + len - 5, ".text") == 0)
+       len -= 5;
+
+      name = xmalloc (len + strlen (base_name) + 1);
+      strcpy (name, text_name);
+      strcpy (name + len, base_name);
     }
 
-  if (!seg)
+  /* 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.  */
+         /* Add the newly created literal segment to the list.  */
          seg_list *n = (seg_list *) xmalloc (sizeof (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));
+
+      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 (stdoutput, seg, flags);
       bfd_set_section_alignment (stdoutput, seg, 2);
     }
 
-  *pseg = seg;
+  *pcached = seg;
   subseg_set (current_section, current_subsec);
+  return seg;
 }
 
 \f
@@ -10343,7 +10129,6 @@ static void xtensa_create_property_segments
 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 void add_xt_block_frags
@@ -10361,16 +10146,13 @@ 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 ();
 
-  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);
@@ -10419,9 +10201,8 @@ xtensa_create_property_segments (frag_predicate property_function,
 
       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);
+         segT insn_sec = 
+           xtensa_get_property_section (sec, section_name_base);
          segment_info_type *xt_seg_info = retrieve_segment_info (insn_sec);
          xtensa_block_info **xt_blocks =
            &xt_seg_info->tc_segment_info_data.blocks[sec_type];
@@ -10449,7 +10230,7 @@ xtensa_create_property_segments (frag_predicate property_function,
          xtensa_block_info *cur_block;
          /* This is a section with some data.  */
          int num_recs = 0;
-         size_t rec_size;
+         bfd_size_type rec_size;
 
          for (cur_block = block; cur_block; cur_block = cur_block->next)
            num_recs++;
@@ -10466,7 +10247,7 @@ xtensa_create_property_segments (frag_predicate property_function,
            {
              /* Allocate a fragment and leak it.  */
              fragS *fragP;
-             size_t frag_size;
+             bfd_size_type frag_size;
              fixS *fixes;
              frchainS *frchainP;
              int i;
@@ -10545,16 +10326,15 @@ xtensa_create_xproperty_segments (frag_flags_fn flag_fn,
       flagword flags;
 
       flags = bfd_get_section_flags (stdoutput, sec);
-      if (flags & SEC_DEBUGGING)
-       continue;
-      if (!(flags & SEC_ALLOC))
+      if ((flags & SEC_DEBUGGING)
+         || !(flags & SEC_ALLOC)
+         || (flags & SEC_MERGE))
        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);
+         segT insn_sec =
+           xtensa_get_property_section (sec, section_name_base);
          segment_info_type *xt_seg_info = retrieve_segment_info (insn_sec);
          xtensa_block_info **xt_blocks =
            &xt_seg_info->tc_segment_info_data.blocks[sec_type];
@@ -10581,7 +10361,7 @@ xtensa_create_xproperty_segments (frag_flags_fn flag_fn,
          xtensa_block_info *cur_block;
          /* This is a section with some data.  */
          int num_recs = 0;
-         size_t rec_size;
+         bfd_size_type rec_size;
 
          for (cur_block = block; cur_block; cur_block = cur_block->next)
            num_recs++;
@@ -10599,7 +10379,7 @@ xtensa_create_xproperty_segments (frag_flags_fn flag_fn,
            {
              /* Allocate a fragment and (unfortunately) leak it.  */
              fragS *fragP;
-             size_t frag_size;
+             bfd_size_type frag_size;
              fixS *fixes;
              frchainS *frchainP;
              int i;
@@ -10677,24 +10457,12 @@ retrieve_segment_info (segT seg)
       seginfo->bfd_section = seg;
       seginfo->sym = 0;
       /* We will not be dealing with these, only our special ones.  */
-#if 0
-      if (seg == bfd_abs_section_ptr)
-       abs_seg_info = seginfo;
-      else if (seg == bfd_und_section_ptr)
-       und_seg_info = seginfo;
-      else
-#endif
-       bfd_set_section_userdata (stdoutput, seg, (void *) seginfo);
-#if 0
-      seg_fix_rootP = &segment_info[seg].fix_root;
-      seg_fix_tailP = &segment_info[seg].fix_tail;
-#endif
+      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;
@@ -10710,29 +10478,6 @@ retrieve_segment_info (segT seg)
 }
 
 
-static segT
-retrieve_xtensa_section (char *sec_name)
-{
-  bfd *abfd = stdoutput;
-  flagword flags, out_flags, link_once_flags;
-  segT s;
-
-  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);
-
-  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);
-
-  return s;
-}
-
-
 static bfd_boolean
 section_has_property (segT sec, frag_predicate property_function)
 {
@@ -10974,7 +10719,7 @@ static bfd_vma
 xt_block_aligned_size (const xtensa_block_info *xt_block)
 {
   bfd_vma end_addr;
-  size_t align_bits;
+  unsigned align_bits;
 
   if (!xt_block->flags.is_align)
     return xt_block->size;
@@ -11114,12 +10859,9 @@ init_op_placement_info_table (void)
       /* FIXME: Make tinsn allocation dynamic.  */
       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;
@@ -11134,25 +10876,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;
                    }
                }
            }
@@ -11176,15 +10908,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
@@ -11247,7 +10985,7 @@ istack_push_space (IStack *stack)
   TInsn *insn;
   assert (!istack_full (stack));
   insn = &stack->insn[rec];
-  memset (insn, 0, sizeof (TInsn));
+  tinsn_init (insn);
   stack->ninsn++;
   return insn;
 }
@@ -11262,7 +11000,7 @@ istack_pop (IStack *stack)
   int rec = stack->ninsn - 1;
   assert (!istack_empty (stack));
   stack->ninsn--;
-  memset (&stack->insn[rec], 0, sizeof (TInsn));
+  tinsn_init (&stack->insn[rec]);
 }
 
 \f
@@ -11275,17 +11013,6 @@ 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
@@ -11337,18 +11064,12 @@ 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));
+             as_bad (_("invalid symbolic operand"));
              return TRUE;
            }
        }
@@ -11387,92 +11108,13 @@ tinsn_has_complex_operands (const TInsn *insn)
 }
 
 
-/* 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;
-  int 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;
-       }
-    }
-
-  xtensa_format_encode (isa, fmt, insnbuf);
-  xtensa_format_set_slot (isa, fmt, 0, insnbuf, slotbuf);
-
-  return has_fixup;
-}
-
-
-/* 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
-
-   The return value tells whether there are any remaining O_symbols.  */
+/* 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.  */
 
 static bfd_boolean
 tinsn_to_slotbuf (xtensa_format fmt,
@@ -11486,8 +11128,6 @@ tinsn_to_slotbuf (xtensa_format fmt,
   int noperands = xtensa_opcode_num_operands (isa, opcode);
   int i;
 
-  *((int *) &slotbuf[0]) = 0;
-  *((int *) &slotbuf[1]) = 0;
   assert (tinsn->insn_type == ITYPE_INSN);
   if (noperands != tinsn->ntok)
     as_fatal (_("operand number mismatch"));
@@ -11502,7 +11142,8 @@ tinsn_to_slotbuf (xtensa_format fmt,
   for (i = 0; i < noperands; i++)
     {
       expressionS *expr = &tinsn->tok[i];
-      int rc, line;
+      int rc;
+      unsigned line;
       char *file_name;
       uint32 opnd_value;
 
@@ -11541,6 +11182,44 @@ 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 bfd_boolean
+tinsn_to_insnbuf (TInsn *tinsn, xtensa_insnbuf insnbuf)
+{
+  static xtensa_insnbuf slotbuf = 0;
+  static vliw_insn vinsn;
+  xtensa_isa isa = xtensa_default_isa;
+  bfd_boolean has_fixup = FALSE;
+  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
@@ -11621,21 +11300,9 @@ tinsn_immed_from_frag (TInsn *tinsn, fragS *fragP, int 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]);
-       }
+      set_expr_symbol_offset (&tinsn->tok[opnum],
+                             fragP->tc_frag_data.slot_symbols[slot],
+                             fragP->tc_frag_data.slot_offsets[slot]);
     }
 }
 
@@ -11688,8 +11355,6 @@ xg_init_vinsn (vliw_insn *v)
 
   for (i = 0; i < 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"));
@@ -11701,6 +11366,9 @@ static void
 xg_clear_vinsn (vliw_insn *v)
 {
   int i;
+
+  memset (v, 0, offsetof (vliw_insn, insnbuf));
+
   v->format = XTENSA_UNDEFINED;
   v->num_slots = 0;
   v->inside_bundle = FALSE;
@@ -11709,10 +11377,7 @@ xg_clear_vinsn (vliw_insn *v)
     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;
-    }
+    v->slots[i].opcode = XTENSA_UNDEFINED;
 }
 
 
@@ -11720,7 +11385,7 @@ static bfd_boolean
 vinsn_has_specific_opcodes (vliw_insn *v)
 {
   int i;
-  
+
   for (i = 0; i < v->num_slots; i++)
     {
       if (v->slots[i].is_specific_opcode)
@@ -11740,17 +11405,8 @@ xg_free_vinsn (vliw_insn *v)
 }
 
 
-/* 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
-
-   The return value tells whether there are any remaining O_symbols.  */
+/* Encode a vliw_insn into an insnbuf.  Return TRUE if there are any symbolic
+   operands.  See also the assumptions listed for tinsn_to_slotbuf.  */
 
 static bfd_boolean
 vinsn_to_insnbuf (vliw_insn *vinsn,
@@ -11775,14 +11431,7 @@ vinsn_to_insnbuf (vliw_insn *vinsn,
 
       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 (tinsn_has_fixup)
        {
          int i;
          xtensa_opcode opcode = tinsn->opcode;
@@ -11799,48 +11448,35 @@ vinsn_to_insnbuf (vliw_insn *vinsn,
                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, expr, fragP,
+                                            frag_offset - fragP->fr_literal);
                        }
                      else
                        {
+                         if (expr->X_op != O_symbol)
+                           as_bad (_("invalid operand"));
                          tinsn->symbol = expr->X_add_symbol;
                          tinsn->offset = expr->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;
                }
            }
@@ -11866,7 +11502,7 @@ vinsn_from_chars (vliw_insn *vinsn, char *f)
       slotbuf = xtensa_insnbuf_alloc (isa);
     }
 
-  xtensa_insnbuf_from_chars (isa, insnbuf, f, 0);
+  xtensa_insnbuf_from_chars (isa, insnbuf, (unsigned char *) f, 0);
   fmt = xtensa_format_decode (isa, insnbuf);
   if (fmt == XTENSA_UNDEFINED)
     as_fatal (_("cannot decode instruction format"));
@@ -11946,21 +11582,6 @@ 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
This page took 0.108157 seconds and 4 git commands to generate.