* cgen.h: New file.
authorDoug Evans <dje@google.com>
Thu, 7 May 1998 09:31:42 +0000 (09:31 +0000)
committerDoug Evans <dje@google.com>
Thu, 7 May 1998 09:31:42 +0000 (09:31 +0000)
* cgen.c: Include it.
(MAX_FIXUPS): Renamed to CGEN_MAX_FIXUPS.
(cgen_asm_finish_insn): Result is now void.  New arg `result'.
All callers updated.
* config/tc-m32r.c: Include cgen.h.
(m23r_insn): New members num_fixups,fixups.
(assemble_parallel_insn): Initialize debug_sym_link for each insn.
(md_assemble): Simplify code to pack two insns in parallel.
When swapping two insns, update their fixups.

gas/.Sanitize
gas/ChangeLog
gas/cgen.c
gas/config/tc-m32r.c

index b51684ef3d9e5f890267a4195ee687946fc07332..344d4b7fd3fdd664e7c6401a996f529b41ce7fc3 100644 (file)
@@ -51,6 +51,7 @@ bignum-copy.c
 bignum.h
 bit_fix.h
 cgen.c
+cgen.h
 cond.c
 config
 config-gas.com
index e3df01e4057134b0aa0ddf3142e43ccd077204be..22b3e6051d1d3f4940eac992508748b915ee71d8 100644 (file)
@@ -1,3 +1,18 @@
+Thu May  7 02:19:14 1998  Doug Evans  <devans@charmed.cygnus.com>
+
+       * cgen.h: New file.
+       * cgen.c: Include it.
+       (MAX_FIXUPS): Renamed to CGEN_MAX_FIXUPS.
+       (cgen_asm_finish_insn): Result is now void.  New arg `result'.
+       All callers updated.
+       * config/tc-m32r.c: Include cgen.h.
+       (m23r_insn): New members num_fixups,fixups.
+start-sanitize-m32rx
+       (assemble_parallel_insn): Initialize debug_sym_link for each insn.
+       (md_assemble): Simplify code to pack two insns in parallel.
+       When swapping two insns, update their fixups.
+end-sanitize-m32rx
+
 start-sanitize-sky
 Wed May  6 16:26:57 1998  Doug Evans  <devans@canuck.cygnus.com>
 
index 3e1885ec12658a01dad356d8497e270ceedd6744..e9954a1a58998ab9e6b11519cbc21556e3f5009c 100644 (file)
@@ -24,6 +24,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
 #include "cgen-opc.h"
 #include "as.h"
 #include "subsegs.h"
+#include "cgen.h"
 
 /* Callback to insert a register into the symbol table.
    A target may choose to let GAS parse the registers.
@@ -32,7 +33,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
 void
 cgen_asm_record_register (name, number)
      char * name;
-     int    number;
+     int number;
 {
   /* Use symbol_create here instead of symbol_new so we don't try to
      output registers into the object file's symbol table.  */
@@ -53,15 +54,13 @@ cgen_asm_record_register (name, number)
 
 struct fixup
 {
-  int         opindex;
-  int         opinfo;
+  int opindex;
+  int opinfo;
   expressionS exp;
 };
 
-#define MAX_FIXUPS 5
-
-static struct fixup fixups [MAX_FIXUPS];
-static int          num_fixups;
+static struct fixup fixups [CGEN_MAX_FIXUPS];
+static int num_fixups;
 
 /* Prepare to parse an instruction.
    ??? May wish to make this static and delete calls in md_assemble.  */
@@ -80,7 +79,7 @@ cgen_queue_fixup (opindex, opinfo, expP)
      expressionS * expP;
 {
   /* We need to generate a fixup for this expression.  */
-  if (num_fixups >= MAX_FIXUPS)
+  if (num_fixups >= CGEN_MAX_FIXUPS)
     as_fatal (_("too many fixups"));
   fixups[num_fixups].exp     = * expP;
   fixups[num_fixups].opindex = opindex;
@@ -92,8 +91,8 @@ cgen_queue_fixup (opindex, opinfo, expP)
    and to have this backup be swapped with the current chain.  This allows
    certain ports, eg the m32r, to swap two instructions and swap their fixups
    at the same time.  */
-static struct fixup saved_fixups [MAX_FIXUPS];
-static int          saved_num_fixups;
+static struct fixup saved_fixups [CGEN_MAX_FIXUPS];
+static int saved_num_fixups;
 
 void
 cgen_save_fixups ()
@@ -118,7 +117,7 @@ cgen_restore_fixups ()
 void
 cgen_swap_fixups ()
 {
-  int          tmp;
+  int tmp;
   struct fixup tmp_fixup;
 
   if (num_fixups == 0)
@@ -135,7 +134,7 @@ cgen_swap_fixups ()
       saved_num_fixups = num_fixups;
       num_fixups = tmp;
       
-      for (tmp = MAX_FIXUPS; tmp--;)
+      for (tmp = CGEN_MAX_FIXUPS; tmp--;)
        {
          tmp_fixup          = saved_fixups [tmp];
          saved_fixups [tmp] = fixups [tmp];
@@ -235,23 +234,23 @@ static jmp_buf expr_jmp_buf;
 
 const char *
 cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP)
-     enum cgen_parse_operand_type     want;
-     const char **                    strP;
-     int                              opindex;
-     int                              opinfo;
+     enum cgen_parse_operand_type want;
+     const char ** strP;
+     int opindex;
+     int opinfo;
      enum cgen_parse_operand_result * resultP;
-     bfd_vma *                        valueP;
+     bfd_vma * valueP;
 {
 #ifdef __STDC__
-  /* These is volatile to survive the setjmp.  */
-  char * volatile                           hold;
+  /* These are volatile to survive the setjmp.  */
+  char * volatile hold;
   enum cgen_parse_operand_result * volatile resultP_1;
 #else
-  static char *                             hold;
-  static enum cgen_parse_operand_result *   resultP_1;
+  static char * hold;
+  static enum cgen_parse_operand_result * resultP_1;
 #endif
-  const char *                              errmsg = NULL;
-  expressionS                               exp;
+  const char * errmsg = NULL;
+  expressionS exp;
 
   if (want == CGEN_PARSE_OPERAND_INIT)
     {
@@ -322,18 +321,23 @@ cgen_md_operand (expressionP)
 /* Finish assembling instruction INSN.
    BUF contains what we've built up so far.
    LENGTH is the size of the insn in bits.
+   RELAX_P is non-zero if relaxable insns should be emitted as such.
+   Otherwise they're emitted in non-relaxable forms.
+   The "result" is stored in RESULT if non-NULL.
    Returns the address of the buffer containing the assembled instruction,
    in case the caller needs to modify it for some reason. */
 
-char *
-cgen_asm_finish_insn (insn, buf, length)
+void
+cgen_asm_finish_insn (insn, buf, length, relax_p, result)
      const CGEN_INSN * insn;
-     cgen_insn_t *     buf;
-     unsigned int      length;
+     cgen_insn_t * buf;
+     unsigned int length;
+     int relax_p;
+     finished_insn * result;
 {
-  int          i;
-  int          relax_operand;
-  char *       f;
+  int i;
+  int relax_operand;
+  char * f;
   unsigned int byte_len = length / 8;
 
   /* ??? Target foo issues various warnings here, so one might want to provide
@@ -354,7 +358,7 @@ cgen_asm_finish_insn (insn, buf, length)
   /* Is there a relaxable insn with the relaxable operand needing a fixup?  */
 
   relax_operand = -1;
-  if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0)
+  if (relax_p && CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0)
     {
       /* Scan the fixups for the operand affected by relaxing
         (i.e. the branch address).  */
@@ -372,7 +376,7 @@ cgen_asm_finish_insn (insn, buf, length)
 
   if (relax_operand != -1)
     {
-      int     max_len;
+      int max_len;
       fragS * old_frag;
 
 #ifdef TC_CGEN_MAX_RELAX
@@ -405,9 +409,15 @@ cgen_asm_finish_insn (insn, buf, length)
       old_frag->fr_cgen.insn    = insn;
       old_frag->fr_cgen.opindex = fixups[relax_operand].opindex;
       old_frag->fr_cgen.opinfo  = fixups[relax_operand].opinfo;
+      if (result)
+       result->frag = old_frag;
     }
   else
-    f = frag_more (byte_len);
+    {
+      f = frag_more (byte_len);
+      if (result)
+       result->frag = frag_now;
+    }
 
   /* If we're recording insns as numbers (rather than a string of bytes),
      target byte order handling is deferred until now.  */
@@ -436,10 +446,13 @@ cgen_asm_finish_insn (insn, buf, length)
   /* Create any fixups.  */
   for (i = 0; i < num_fixups; ++i)
     {
+      fixS * fixP;
+
       /* Don't create fixups for these.  That's done during relaxation.
         We don't need to test for CGEN_INSN_RELAX as they can't get here
         (see above).  */
-      if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0
+      if (relax_p
+         && CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0
          && CGEN_OPERAND_ATTR (& CGEN_SYM (operand_table) [fixups[i].opindex],
                                CGEN_OPERAND_RELAX) != 0)
        continue;
@@ -448,14 +461,20 @@ cgen_asm_finish_insn (insn, buf, length)
 #define md_cgen_record_fixup_exp cgen_record_fixup_exp
 #endif
 
-      md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal,
-                               insn, length,
-                               & CGEN_SYM (operand_table) [fixups[i].opindex],
-                               fixups[i].opinfo,
-                               & fixups[i].exp);
+       fixP = md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal,
+                                        insn, length,
+                                        & CGEN_SYM (operand_table) [fixups[i].opindex],
+                                        fixups[i].opinfo,
+                                        & fixups[i].exp);
+       if (result)
+         result->fixups[i] = fixP;
     }
 
-  return f;
+  if (result)
+    {
+      result->num_fixups = num_fixups;
+      result->addr = f;
+    }
 }
 
 /* Apply a fixup to the object code.  This is called for all the
index aee758336d02e9ebeb4c97866dedb1c05ebf5be9..31c491587d300b1cc9dc9199960ebb084075be6d 100644 (file)
 #include "subsegs.h"     
 #include "symcat.h"
 #include "cgen-opc.h"
+#include "cgen.h"
 
+/* Linked list of symbols that are debugging symbols to be defined as the
+   beginning of the current instruction.  */
+typedef struct sym_link
+{
+  struct sym_link *next;
+  symbolS        *symbol;
+} sym_linkS;
+
+static sym_linkS *debug_sym_link = (sym_linkS *)0;
+  
 /* Structure to hold all of the different components describing an individual instruction.  */
 typedef struct
 {
@@ -38,7 +49,10 @@ typedef struct
 #endif
   char *               addr;
   fragS *              frag;
+  int                   num_fixups;
+  fixS *                fixups [CGEN_MAX_FIXUPS];
   int                   indices [MAX_OPERAND_INSTANCES];
+  sym_linkS            *debug_sym_link;
 }
 m32r_insn;
 
@@ -69,10 +83,8 @@ static int enable_m32rx = 0;
    instruction might have constraint violations.  */
 static int warn_explicit_parallel_conflicts = 1;
 
-/* start-sanitize-phase2-m32rx */
 /* Non-zero if insns can be made parallel.  */
 static int optimize;
-/* end-sanitize-phase2-m32rx */
 /* end-sanitize-m32rx */
 
 /* stuff for .scomm symbols.  */
@@ -124,10 +136,10 @@ allow_m32rx (on)
 /* end-sanitize-m32rx */
 \f
 #define M32R_SHORTOPTS ""
-/* start-sanitize-phase2-m32rx */
+/* start-sanitize-m32rx */
 #undef M32R_SHORTOPTS
 #define M32R_SHORTOPTS "O"
-/* end-sanitize-phase2-m32rx */
+/* end-sanitize-m32rx */
 const char * md_shortopts = M32R_SHORTOPTS;
 
 struct option md_longopts[] =
@@ -162,11 +174,9 @@ md_parse_option (c, arg)
   switch (c)
     {
 /* start-sanitize-m32rx */
-/* start-sanitize-phase2-m32rx */
     case 'O':
       optimize = 1;
       break;
-/* end-sanitize-phase2-m32rx */
 
     case OPTION_M32RX:
       allow_m32rx (1);
@@ -204,10 +214,8 @@ md_show_usage (stream)
   fprintf (stream, _("\
 --m32rx                        support the extended m32rx instruction set\n"));
 
-/* start-sanitize-phase2-m32rx */
   fprintf (stream, _("\
 -O                     try to combine instructions in parallel\n"));
-/* end-sanitize-phase2-m32rx */
 
   fprintf (stream, _("\
 --warn-explicit-parallel-conflicts     warn when parallel instrucitons violate contraints\n"));
@@ -229,6 +237,8 @@ md_show_usage (stream)
 
 static void fill_insn PARAMS ((int));
 static void m32r_scomm PARAMS ((int));
+static void debug_sym PARAMS ((int));
+static void expand_debug_syms PARAMS ((sym_linkS *, int));
 
 /* Set by md_assemble for use by m32r_fill_insn.  */
 static subsegT prev_subseg;
@@ -237,12 +247,13 @@ static segT prev_seg;
 /* The target specific pseudo-ops which we support.  */
 const pseudo_typeS md_pseudo_table[] =
 {
-  { "word", cons, 4 },
-  { "fillinsn", fill_insn, 0 },
-  { "scomm", m32r_scomm, 0 },
+  { "word",    cons,           4 },
+  { "fillinsn", fill_insn,     0 },
+  { "scomm",   m32r_scomm,     0 },
+  { "debugsym",        debug_sym,      0 },
 /* start-sanitize-m32rx */
-  { "m32r",  allow_m32rx, 0},
-  { "m32rx", allow_m32rx, 1},
+  { "m32r",    allow_m32rx,    0 },
+  { "m32rx",   allow_m32rx,    1 },
 /* end-sanitize-m32rx */
   { NULL, NULL, 0 }
 };
@@ -324,6 +335,77 @@ fill_insn (ignore)
   seen_relaxable_p = 0;
 }
 
+/* Record the symbol so that when we output the insn, we can create
+   a symbol that is at the start of the instruction.  This is used
+   to emit the label for the start of a breakpoint without causing
+   the assembler to emit a NOP if the previous instruction was a
+   16 bit instruction.  */
+
+static void
+debug_sym (ignore)
+     int ignore;
+{
+  register char *name;
+  register char delim;
+  register char *end_name;
+  register symbolS *symbolP;
+  register sym_linkS *link;
+
+  name = input_line_pointer;
+  delim = get_symbol_end ();
+  end_name = input_line_pointer;
+  if ((symbolP = symbol_find (name)) == NULL
+      && (symbolP = md_undefined_symbol (name)) == NULL)
+    {
+      symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
+    }
+
+  symbol_table_insert (symbolP);
+  if (S_IS_DEFINED (symbolP) && S_GET_SEGMENT (symbolP) != reg_section)
+    as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
+
+  else
+    {
+      link = (sym_linkS *) xmalloc (sizeof (sym_linkS));
+      link->symbol = symbolP;
+      link->next = debug_sym_link;
+      debug_sym_link = link;
+      symbolP->local = 1;
+    }
+
+  *end_name = delim;
+  demand_empty_rest_of_line ();
+}
+
+/* Second pass to expanding the debug symbols, go through linked
+   list of symbols and reassign the address.  */
+
+static void
+expand_debug_syms (syms, align)
+     sym_linkS *syms;
+     int align;
+{
+  char *save_input_line = input_line_pointer;
+  sym_linkS *next_syms;
+  expressionS exp;
+
+  if (!syms)
+    return;
+
+  (void) m32r_do_align (align, NULL, 0, 0);
+  for (; syms != (sym_linkS *)0; syms = next_syms)
+    {
+      symbolS *symbolP = syms->symbol;
+      next_syms = syms->next;
+      input_line_pointer = ".\n";
+      pseudo_set (symbolP);
+      free ((char *)syms);
+    }
+
+  input_line_pointer = save_input_line;
+}
+
 /* Cover function to fill_insn called after a label and at end of assembly.
 
    The result is always 1: we're called in a conditional to see if the
@@ -608,6 +690,9 @@ assemble_parallel_insn (str, str2)
   if (prev_insn.insn)
     fill_insn (0);
 
+  first.debug_sym_link = debug_sym_link;
+  debug_sym_link = (sym_linkS *)0;
+
   /* Parse the first instruction.  */
   if (! (first.insn = CGEN_SYM (assemble_insn)
         (str, & first.fields, first.buffer, & errmsg)))
@@ -656,6 +741,8 @@ assemble_parallel_insn (str, str2)
   if (first.insn == NULL)
     as_fatal (_("internal error: m32r_cgen_lookup_get_insn_operands failed for first insn"));
 
+  second.debug_sym_link = NULL;
+
   /* Parse the second instruction.  */
   if (! (second.insn = CGEN_SYM (assemble_insn)
         (str, & second.fields, second.buffer, & errmsg)))
@@ -721,8 +808,9 @@ assemble_parallel_insn (str, str2)
       cgen_swap_fixups ();
 
       /* Write it out.  */
-      (void) cgen_asm_finish_insn (first.orig_insn, first.buffer,
-                                  CGEN_FIELDS_BITSIZE (& first.fields), 0);
+      expand_debug_syms (first.debug_sym_link, 1);
+      cgen_asm_finish_insn (first.orig_insn, first.buffer,
+                           CGEN_FIELDS_BITSIZE (& first.fields), 0, NULL);
       
       /* Force the top bit of the second insn to be set.  */
       make_parallel (second.buffer);
@@ -731,15 +819,17 @@ assemble_parallel_insn (str, str2)
       cgen_restore_fixups ();
 
       /* Write it out.  */
-      (void) cgen_asm_finish_insn (second.orig_insn, second.buffer,
-                                  CGEN_FIELDS_BITSIZE (& second.fields), 0);
+      expand_debug_syms (second.debug_sym_link, 1);
+      cgen_asm_finish_insn (second.orig_insn, second.buffer,
+                           CGEN_FIELDS_BITSIZE (& second.fields), 0, NULL);
     }
   /* Try swapping the instructions to see if they work that way.  */
   else if (can_make_parallel (& second, & first) == NULL)
     {
       /* Write out the second instruction first.  */
-      (void) cgen_asm_finish_insn (second.orig_insn, second.buffer,
-                                  CGEN_FIELDS_BITSIZE (& second.fields), 0);
+      expand_debug_syms (second.debug_sym_link, 1);
+      cgen_asm_finish_insn (second.orig_insn, second.buffer,
+                           CGEN_FIELDS_BITSIZE (& second.fields), 0, NULL);
       
       /* Force the top bit of the first instruction to be set.  */
       make_parallel (first.buffer);
@@ -748,8 +838,9 @@ assemble_parallel_insn (str, str2)
       cgen_restore_fixups ();
 
       /* Write out the first instruction.  */
-      (void) cgen_asm_finish_insn (first.orig_insn, first.buffer,
-                                  CGEN_FIELDS_BITSIZE (& first.fields), 0);
+      expand_debug_syms (first.debug_sym_link, 1);
+      cgen_asm_finish_insn (first.orig_insn, first.buffer,
+                           CGEN_FIELDS_BITSIZE (& first.fields), 0, NULL);
     }
   else
     {
@@ -785,6 +876,9 @@ md_assemble (str)
     }
 /* end-sanitize-m32rx */
   
+  insn.debug_sym_link = debug_sym_link;
+  debug_sym_link = (sym_linkS *)0;
+
   insn.insn = CGEN_SYM (assemble_insn) (str, & insn.fields, insn.buffer, & errmsg);
   if (!insn.insn)
     {
@@ -810,26 +904,28 @@ md_assemble (str)
          fill_insn (0);
        }
 
+      expand_debug_syms (insn.debug_sym_link, 2);
+
       /* Doesn't really matter what we pass for RELAX_P here.  */
-      (void) cgen_asm_finish_insn (insn.insn, insn.buffer,
-                                  CGEN_FIELDS_BITSIZE (& insn.fields), 1);
+      cgen_asm_finish_insn (insn.insn, insn.buffer,
+                           CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
     }
   else
     {
+      int on_32bit_boundary_p;
 /* start-sanitize-m32rx */
-/* start-sanitize-phase2-m32rx */
       int swap = false;
-/* end-sanitize-phase2-m32rx */
 /* end-sanitize-m32rx */
 
       if (CGEN_INSN_BITSIZE (insn.insn) != 16)
        abort();
 
+      insn.orig_insn = insn.insn;
+/* start-sanitize-m32rx */
       if (enable_m32rx)
        {
          /* Get the indices of the operands of the instruction.
             FIXME: See assemble_parallel for notes on orig_insn.  */
-         insn.orig_insn = insn.insn;
          insn.insn = m32r_cgen_lookup_get_insn_operands (NULL,
                                                          bfd_getb16 ((char *) insn.buffer),
                                                          16,
@@ -837,58 +933,61 @@ md_assemble (str)
          if (insn.insn == NULL)
            as_fatal (_("internal error: m32r_cgen_get_insn_operands failed"));
        }
-      else
-       insn.orig_insn = insn.insn;
+/* end-sanitize-m32rx */
 
-      /* Keep track of whether we've seen a pair of 16 bit insns.
+      /* Compute whether we're on a 32 bit boundary or not.
         prev_insn.insn is NULL when we're on a 32 bit boundary.  */
-      if (prev_insn.insn)
-       {
-/* start-sanitize-m32rx */
-/* start-sanitize-phase2-m32rx */
-         /* Look to see if this instruction can be combined with the
-            previous instruction to make one, parallel, 32 bit instruction.
-            If the previous instruction (potentially) changed the flow of
-            program control, then it cannot be combined with the current
-            instruction.  If the current instruction is relaxable, then it
-            might be replaced with a longer version, so we cannot combine it.
-            Also if the output of the previous instruction is used as an
-            input to the current instruction then it cannot be combined.
-            Otherwise call can_make_parallel() with both orderings of the
-            instructions to see if they can be combined.  */
-         if (     enable_m32rx
-             &&   optimize
-             &&   CGEN_INSN_ATTR (insn.orig_insn, CGEN_INSN_RELAXABLE) == 0
-             && ! writes_to_pc (& prev_insn)
-             && ! first_writes_to_seconds_operands (& prev_insn, &insn, false)
-                )
-           {
-             if (can_make_parallel (& prev_insn, & insn) == NULL)
-               make_parallel (insn.buffer);
-             else if (can_make_parallel (& insn, & prev_insn) == NULL)
-               swap = true;
-           }
-/* end-sanitize-phase2-m32rx */
-/* end-sanitize-m32rx */
+      on_32bit_boundary_p = prev_insn.insn == NULL;
 
-         prev_insn.insn = NULL;
-       }
-      else
+/* start-sanitize-m32rx */
+      /* Look to see if this instruction can be combined with the
+        previous instruction to make one, parallel, 32 bit instruction.
+        If the previous instruction (potentially) changed the flow of
+        program control, then it cannot be combined with the current
+        instruction.  If the current instruction is relaxable, then it
+        might be replaced with a longer version, so we cannot combine it.
+        Also if the output of the previous instruction is used as an
+        input to the current instruction then it cannot be combined.
+        Otherwise call can_make_parallel() with both orderings of the
+        instructions to see if they can be combined.  */
+      if (     ! on_32bit_boundary_p
+         &&   enable_m32rx
+         &&   optimize
+         &&   CGEN_INSN_ATTR (insn.orig_insn, CGEN_INSN_RELAXABLE) == 0
+         && ! writes_to_pc (& prev_insn)
+         && ! first_writes_to_seconds_operands (& prev_insn, &insn, false)
+         )
        {
-         prev_insn = insn;
+         if (can_make_parallel (& prev_insn, & insn) == NULL)
+           make_parallel (insn.buffer);
+         else if (can_make_parallel (& insn, & prev_insn) == NULL)
+           swap = true;
        }
+/* end-sanitize-m32rx */
+
+      expand_debug_syms (insn.debug_sym_link, 1);
 
-      /* Record the frag that might be used by this insn.  */
-      insn.frag = frag_now;
-      insn.addr = cgen_asm_finish_insn (insn.orig_insn, insn.buffer,
-                                       CGEN_FIELDS_BITSIZE (& insn.fields),
-                                       1 /*relax_p*/);
+      {
+       int i;
+       finished_insnS fi;
+
+       /* Ensure each pair of 16 bit insns is in the same frag.  */
+       frag_grow (4);
+
+       cgen_asm_finish_insn (insn.orig_insn, insn.buffer,
+                             CGEN_FIELDS_BITSIZE (& insn.fields),
+                             1 /*relax_p*/, &fi);
+       insn.addr = fi.addr;
+       insn.frag = fi.frag;
+       insn.num_fixups = fi.num_fixups;
+       for (i = 0; i < fi.num_fixups; ++i)
+         insn.fixups[i] = fi.fixups[i];
+      }
 
 /* start-sanitize-m32rx */
-/* start-sanitize-phase2-m32rx */
       if (swap)
        {
-         int tmp;
+         int i,tmp;
 
 #define SWAP_BYTES(a,b) tmp = a; a = b; b = tmp
 
@@ -899,21 +998,32 @@ md_assemble (str)
          make_parallel (insn.addr);
 
          /* Swap any relaxable frags recorded for the two insns.  */
+         /* FIXME: Clarify.  relaxation precludes parallel insns */
          if (prev_insn.frag->fr_opcode == prev_insn.addr)
            prev_insn.frag->fr_opcode = insn.addr;
          else if (insn.frag->fr_opcode == insn.addr)
            insn.frag->fr_opcode = prev_insn.addr;
-       }
-/* end-sanitize-phase2-m32rx */
 
-      /* Record where this instruction was assembled.  */
-      prev_insn.addr = insn.addr;
-      prev_insn.frag = insn.frag;
+         /* Update the addresses in any fixups.
+            Note that we don't have to handle the case where each insn is in
+            a different frag as we ensure they're in the same frag above.  */
+         for (i = 0; i < prev_insn.num_fixups; ++i)
+           prev_insn.fixups[i]->fx_where += 2;
+         for (i = 0; i < insn.num_fixups; ++i)
+           insn.fixups[i]->fx_where -= 2;
+       }
 /* end-sanitize-m32rx */
+
+      /* Keep track of whether we've seen a pair of 16 bit insns.
+        prev_insn.insn is NULL when we're on a 32 bit boundary.  */
+      if (on_32bit_boundary_p)
+       prev_insn = insn;
+      else
+       prev_insn.insn = NULL;
       
       /* If the insn needs the following one to be on a 32 bit boundary
         (e.g. subroutine calls), fill this insn's slot.  */
-      if (prev_insn.insn != NULL
+      if (on_32bit_boundary_p
          && CGEN_INSN_ATTR (insn.orig_insn, CGEN_INSN_FILL_SLOT) != 0)
        fill_insn (0);