gas/
[deliverable/binutils-gdb.git] / gas / config / tc-xtensa.c
index 53d3bad139ff2d780c02528b7e49040ca236c600..a44c28093efaedfe64d089c984d397cde0cfa77b 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-xtensa.c -- Assemble Xtensa instructions.
-   Copyright 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -15,8 +15,8 @@
 
    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>
@@ -81,7 +81,7 @@ 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;
 
@@ -322,20 +322,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.  */
@@ -422,7 +416,6 @@ 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_position (int);
 static void xtensa_literal_pseudo (int);
@@ -485,6 +478,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.  */
 
@@ -516,8 +510,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 *);
 
@@ -844,7 +836,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"));
@@ -857,7 +849,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 == '-')
@@ -950,8 +942,8 @@ 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 
+/* 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
@@ -1016,7 +1008,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 },
@@ -1144,7 +1135,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"));
@@ -1154,7 +1145,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;
 
@@ -1212,7 +1203,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
@@ -1363,8 +1354,7 @@ xtensa_end_directive (int ignore ATTRIBUTE_UNUSED)
              s = (lit_state *) state;
              assert (s);
 
-             if (use_literal_section)
-               default_lit_sections = *s;
+             default_lit_sections = *s;
 
              /* free the state storage */
              free (s);
@@ -1385,28 +1375,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
@@ -1927,9 +1895,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;
        }
     }
@@ -1946,7 +1914,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;
@@ -2046,7 +2014,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;
@@ -2707,12 +2675,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;
     }
 
@@ -2992,7 +2964,7 @@ is_unique_insn_expansion (TransitionRule *r)
    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 
+   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.  */
 
@@ -3318,7 +3290,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))
@@ -3344,7 +3316,7 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
   symbolS *sym;
 
   memset (targ, 0, sizeof (TInsn));
-  targ->loc = insn->loc;
+  targ->linenum = insn->linenum;
   switch (bi->typ)
     {
     case INSTR_INSTR:
@@ -3591,10 +3563,10 @@ xg_assembly_relax (IStack *istack,
   /* Walk through all of the single instruction expansions.  */
   while (xg_is_single_relaxable_insn (&current_insn, &single_target, FALSE))
     {
+      steps_taken++;
       if (xg_symbolic_immeds_fit (&single_target, pc_seg, pc_frag, pc_offset,
                                  stretch))
        {
-         steps_taken++;
          if (steps_taken >= min_steps)
            {
              istack_push (istack, &single_target);
@@ -3743,7 +3715,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;
 
@@ -3800,13 +3772,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"));
@@ -4046,7 +4018,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;
@@ -4159,7 +4131,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;
     }
 
@@ -4169,7 +4141,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;
     }
 
@@ -4203,14 +4175,13 @@ xg_add_opcode_fix (TInsn *tinsn,
   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,
@@ -4219,6 +4190,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);
 
@@ -4226,10 +4198,12 @@ 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;
@@ -4324,7 +4298,7 @@ is_bad_loopend_opcode (const TInsn *tinsn)
       || opcode == xtensa_waiti_opcode
       || opcode == xtensa_rsr_lcount_opcode)
     return TRUE;
-  
+
   return FALSE;
 }
 
@@ -4366,7 +4340,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;
@@ -4403,7 +4377,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);
@@ -4424,7 +4398,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.
@@ -4445,7 +4419,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];
 
@@ -4527,7 +4501,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)
     {
@@ -4715,7 +4689,7 @@ 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;
@@ -4801,9 +4775,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)
@@ -4841,9 +4815,9 @@ 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)
        {
@@ -5026,7 +5000,15 @@ xtensa_init_fix_data (fixS *x)
 void
 xtensa_frob_label (symbolS *sym)
 {
-  float freq = get_subseg_target_freq (now_seg, now_subseg);
+  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.  */
@@ -5050,7 +5032,7 @@ xtensa_frob_label (symbolS *sym)
 
       xtensa_set_frag_assembly_state (frag_now);
       xtensa_move_labels (frag_now, 0, TRUE);
-  }
+    }
 
   /* No target aligning in the absolute section.  */
   if (now_seg != absolute_section
@@ -5079,6 +5061,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);
 }
 
 
@@ -5171,7 +5155,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];
@@ -5260,28 +5244,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:
@@ -5333,7 +5309,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"));
     }
 }
@@ -5542,17 +5518,24 @@ xtensa_fix_adjustable (fixS *fixP)
 
 
 void
-md_apply_fix3 (fixS *fixP, valueT *valP, segT seg)
+md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 {
   char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
-  valueT val;
+  valueT val = 0;
+
+  /* Subtracted symbols are only allowed for a few relocation types, and
+     unless linkrelax is enabled, they should not make it to this point.  */
+  if (fixP->fx_subsy && !(linkrelax && (fixP->fx_r_type == BFD_RELOC_32
+                                       || fixP->fx_r_type == BFD_RELOC_16
+                                       || fixP->fx_r_type == BFD_RELOC_8)))
+    as_bad_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 (linkrelax && fixP->fx_subsy)
+      if (fixP->fx_subsy)
        {
          switch (fixP->fx_r_type)
            {
@@ -5593,8 +5576,9 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg)
          val = *valP;
          fixP->fx_done = 1;
        }
-      else
-       break;
+      /* fall through */
+
+    case BFD_RELOC_XTENSA_PLT:
       md_number_to_chars (fixpos, val, fixP->fx_size);
       fixP->fx_no_overflow = 0; /* Use the standard overflow check.  */
       break;
@@ -5638,7 +5622,6 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg)
        }
       break;
 
-    case BFD_RELOC_XTENSA_PLT:
     case BFD_RELOC_XTENSA_ASM_EXPAND:
     case BFD_RELOC_XTENSA_SLOT0_ALT:
     case BFD_RELOC_XTENSA_SLOT1_ALT:
@@ -5760,11 +5743,11 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 \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,
@@ -5784,15 +5767,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;
@@ -5804,7 +5787,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;
@@ -5816,21 +5799,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);
@@ -5841,20 +5826,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]++;
@@ -5862,34 +5847,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);
@@ -5899,7 +5884,7 @@ 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_reads_and_writes.  */
 
@@ -5913,7 +5898,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
@@ -5942,7 +5927,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 *);
 
 
@@ -5992,7 +5976,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"));
@@ -6070,11 +6054,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);
 
@@ -6090,7 +6074,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"));
@@ -6190,12 +6174,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;
@@ -6225,7 +6209,7 @@ find_vinsn_conflicts (vliw_insn *vinsn)
    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
@@ -6325,7 +6309,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'))
@@ -6333,28 +6317,28 @@ 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);
       int t2_class = xtensa_interface_class_id (isa, t2_int);
 
-      t2_inout = xtensa_interface_inout (isa, j);
+      t2_inout = xtensa_interface_inout (isa, t2_int);
       if (xtensa_interface_has_side_effect (isa, t2_int) == 1)
        t2_volatile = TRUE;
 
@@ -6364,33 +6348,33 @@ check_t1_t2_reads_and_writes (TInsn *t1, TInsn *t2)
            = xtensa_interfaceOperand_interface (isa, t1->opcode, j);
          int t1_class = xtensa_interface_class_id (isa, t1_int);
 
-         t1_inout = xtensa_interface_inout (isa, i);
+         t1_inout = xtensa_interface_inout (isa, t1_int);
          if (xtensa_interface_has_side_effect (isa, t1_int) == 1)
            t1_volatile = TRUE;
 
          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';
        }
     }
-  
+
   return conflict;
 }
 
@@ -6408,6 +6392,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;
@@ -6466,8 +6453,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;
 
@@ -6485,13 +6473,6 @@ relaxation_requirements (vliw_insn *vinsn)
              /* 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
@@ -6504,7 +6485,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)
@@ -6512,59 +6493,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);
+  int slot, chosen_slot;
 
-  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;
-    }
+  vinsn->format = xg_get_single_format (tinsn->opcode);
+  assert (vinsn->format != XTENSA_UNDEFINED);
+  vinsn->num_slots = xtensa_format_num_slots (isa, vinsn->format);
 
-  v.slots[slot] = *orig_insn;
-  slot++;
-
-  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);
 }
 
 
@@ -6579,10 +6549,10 @@ 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
@@ -6595,7 +6565,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);
@@ -6614,11 +6584,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);
@@ -6647,7 +6623,7 @@ total_frag_text_expansion (fragS *fragP)
 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;
@@ -6656,9 +6632,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)
     {
@@ -6718,10 +6695,10 @@ 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... */
@@ -6729,10 +6706,10 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
   if (xtensa_opcode_is_loop (isa, vinsn->slots[0].opcode) == 1)
     {
       int max_fill;
-      
+
       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);
@@ -6744,10 +6721,10 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
                  frag_now->fr_offset,
                  NULL);
       else
-       frag_var (rs_machine_dependent, 0, 0, 
+       frag_var (rs_machine_dependent, 0, 0,
                  RELAX_CHECK_ALIGN_NEXT_OPCODE, 0, 0, NULL);
       xtensa_set_frag_assembly_state (frag_now);
-      
+
       xtensa_move_labels (frag_now, 0, FALSE);
     }
 
@@ -6773,7 +6750,7 @@ 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)
@@ -6783,20 +6760,24 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
       frag_now->tc_frag_data.is_insn = TRUE;
     }
 
-  vinsn_to_insnbuf (vinsn, f, frag_now, TRUE);
+  vinsn_to_insnbuf (vinsn, f, frag_now, FALSE);
   if (vinsn->format == XTENSA_UNDEFINED)
     return;
 
   xtensa_insnbuf_to_chars (isa, vinsn->insnbuf, (unsigned char *) f, 0);
-  
-  xtensa_dwarf2_emit_insn (insn_size - extra_space, &best_loc);
+
+  /* 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.literal_frags[slot] = tinsn->literal_frag;
       if (tinsn->literal_space != 0)
@@ -6809,8 +6790,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;
     }
 
@@ -6986,7 +6967,7 @@ xtensa_cleanup_align_frags (void)
              && fragP->fr_subtype == RELAX_SLOTS
              && fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
            frag_wane (fragP);
-         if (fragP->fr_type == rs_machine_dependent 
+         if (fragP->fr_type == rs_machine_dependent
              && fragP->fr_subtype == RELAX_UNREACHABLE)
            fragP->tc_frag_data.is_unreachable = TRUE;
        }
@@ -7044,15 +7025,10 @@ xtensa_mark_narrow_branches (void)
              && 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)
@@ -7062,6 +7038,7 @@ xtensa_mark_narrow_branches (void)
                {
                  fragP->fr_subtype = RELAX_SLOTS;
                  fragP->tc_frag_data.slot_subtypes[0] = RELAX_NARROW;
+                 fragP->tc_frag_data.is_aligning_branch = 1;
                }
            }
        }
@@ -7092,8 +7069,14 @@ is_narrow_branch_guaranteed_in_range (fragS *fragP, TInsn *tinsn)
 {
   const expressionS *expr = &tinsn->tok[1];
   symbolS *symbolP = expr->X_add_symbol;
-  fragS *target_frag = symbol_get_frag (symbolP);
   offsetT max_distance = expr->X_add_number;
+  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;
@@ -7134,12 +7117,10 @@ xtensa_mark_zcl_first_insns (void)
 
              /* 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);
-               }
+             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);
            }
        }
     }
@@ -7389,7 +7370,7 @@ xtensa_fix_close_loop_end_frags (void)
                             < REQUIRED_LOOP_DIVIDING_BYTES)
                        {
                          int length = 3;
-                         
+
                          if (fragP->fr_var < length)
                            as_fatal (_("fr_var %lu < length %d"),
                                      (long) fragP->fr_var, length);
@@ -7461,7 +7442,7 @@ unrelaxed_frag_max_size (fragS *fragP)
   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:
@@ -7904,7 +7885,7 @@ get_text_align_fill_size (addressT address,
 
   alignment = (1 << align_pow);
   assert (target_size > 0 && alignment >= (addressT) target_size);
-  
+
   if (!use_nops)
     {
       fill_limit = alignment;
@@ -8024,16 +8005,16 @@ 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.  */
-  
+
   int fill_size = 0;
   int first_insn_size;
   int loop_insn_size;
@@ -8074,7 +8055,7 @@ get_noop_aligned_address (fragS *fragP, addressT address)
   /* If it was 8, then we'll need a larger alignment for the section.  */
   align_power = get_text_align_power (first_insn_size);
   record_alignment (now_seg, align_power);
-  
+
   fill_size = get_text_align_fill_size
     (address + pre_opcode_bytes, align_power, first_insn_size, TRUE,
      fragP->tc_frag_data.is_no_density);
@@ -8289,7 +8270,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;
@@ -8424,7 +8405,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;
@@ -8476,7 +8457,7 @@ find_address_of_next_align_frag (fragS **fragPP,
              return 0;
            }
        }
-      else 
+      else
        {
          /* Just punt if we don't know the type.  */
          *fragPP = fragP;
@@ -8511,13 +8492,20 @@ 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;
 
       if (fragP)
@@ -8526,7 +8514,7 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
       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.  */
          int glob_widens = 0;
          int dnn = 0;
@@ -8536,9 +8524,9 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
            (&fragP, &glob_widens, &dnn, &dw, &glob_pad);
          /* If there is a padable portion, then skip.  */
          if (glob_pad || glob_widens >= (1 << branch_align_power (now_seg)))
-           break;
+           address = 0;
 
-         if (address) 
+         if (address)
            {
              offsetT next_m_diff;
              offsetT next_o_diff;
@@ -8579,15 +8567,15 @@ 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);
-      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;
@@ -8659,7 +8647,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.  */
@@ -8669,7 +8657,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
@@ -8679,7 +8667,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.  */
@@ -8693,7 +8681,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
@@ -8707,7 +8695,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;
@@ -8739,7 +8727,7 @@ 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.  */
@@ -8792,7 +8780,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;
@@ -8807,12 +8794,12 @@ 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))
@@ -9067,14 +9054,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;
   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);
@@ -9110,10 +9096,8 @@ convert_frag_narrow (segT segP, fragS *fragP, xtensa_format fmt, int slot)
     }
 
   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);
@@ -9164,7 +9148,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;
@@ -9172,13 +9155,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;
@@ -9192,20 +9175,20 @@ convert_frag_immed (segT segP,
       bytes = xtensa_format_length (isa, fmt);
       if (bytes >= 4)
        {
-         orig_vinsn.slots[slot].opcode =
-           xtensa_format_slot_nop_opcode (isa, orig_vinsn.format, slot);
-         orig_vinsn.slots[slot].ntok = 0;
+         cur_vinsn.slots[slot].opcode =
+           xtensa_format_slot_nop_opcode (isa, cur_vinsn.format, slot);
+         cur_vinsn.slots[slot].ntok = 0;
        }
       else
        {
          bytes += fragP->tc_frag_data.text_expansion[0];
          assert (bytes == 2 || bytes == 3);
-         build_nop (&orig_vinsn.slots[0], bytes);
+         build_nop (&cur_vinsn.slots[0], bytes);
          fragP->fr_fix += fragP->tc_frag_data.text_expansion[0];
        }
-      vinsn_to_insnbuf (&orig_vinsn, fr_opcode, frag_now, FALSE);
+      vinsn_to_insnbuf (&cur_vinsn, fr_opcode, frag_now, TRUE);
       xtensa_insnbuf_to_chars
-       (isa, orig_vinsn.insnbuf, (unsigned char *) fr_opcode, 0);
+       (isa, cur_vinsn.insnbuf, (unsigned char *) fr_opcode, 0);
       fragP->fr_var = 0;
     }
   else
@@ -9338,39 +9321,31 @@ 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,
+                 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);
                }
              immed_instr += size;
@@ -9388,9 +9363,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)
     {
@@ -9837,7 +9809,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;
@@ -9934,10 +9906,10 @@ xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
 
   static bfd_boolean recursive = FALSE;
   fragS *pool_location = get_literal_pool_location (now_seg);
-  bfd_boolean is_init = 
+  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
@@ -10843,12 +10815,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;
@@ -10868,20 +10837,7 @@ init_op_placement_info_table (void)
                    {
                      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;
                    }
                }
            }
@@ -10905,15 +10861,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
@@ -11066,18 +11028,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;
            }
        }
@@ -11116,92 +11072,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;
-  unsigned line;
-
-  if (!slotbuf)
-    slotbuf = xtensa_insnbuf_alloc (isa);
-
-  assert (tinsn->insn_type == ITYPE_INSN);
-  if (noperands != tinsn->ntok)
-    as_fatal (_("operand number mismatch"));
-
-  if (xtensa_opcode_encode (isa, fmt, 0, slotbuf, opcode))
-    as_fatal (_("cannot encode opcode"));
-
-  for (i = 0; i < noperands; ++i)
-    {
-      expressionS *expr = &tinsn->tok[i];
-      switch (expr->X_op)
-       {
-       case O_register:
-         if (xtensa_operand_is_visible (isa, opcode, i) == 0)
-           break;
-         /* The register number has already been checked in
-            expression_maybe_register, so we don't need to check here.  */
-         opnd_value = expr->X_add_number;
-         (void) xtensa_operand_encode (isa, opcode, i, &opnd_value);
-         xtensa_operand_set_field (isa, opcode, i, fmt, 0,
-                                   slotbuf, opnd_value);
-         break;
-
-       case O_constant:
-         if (xtensa_operand_is_visible (isa, opcode, i) == 0)
-           break;
-         as_where (&file_name, &line);
-         /* It is a constant and we called this function,
-            then we have to try to fit it.  */
-         xtensa_insnbuf_set_operand (slotbuf, fmt, 0, opcode, i,
-                                     expr->X_add_number, file_name, line);
-         break;
-
-       default:
-         has_fixup = TRUE;
-         break;
-       }
-    }
-
-  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,
@@ -11215,8 +11092,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"));
@@ -11271,6 +11146,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
@@ -11351,21 +11264,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]);
     }
 }
 
@@ -11418,8 +11319,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"));
@@ -11431,6 +11330,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;
@@ -11439,10 +11341,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;
 }
 
 
@@ -11450,7 +11349,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)
@@ -11470,17 +11369,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,
@@ -11505,14 +11395,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;
@@ -11529,48 +11412,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;
                }
            }
@@ -11676,21 +11546,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.053748 seconds and 4 git commands to generate.