* gdb.threads/bp_in_thread.exp: New testcase.
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index da0ea769970cdd4f002f1fc8d04697c1c05533fa..fd76eabb5ac80dd9b380a8690073cfb0b3628118 100644 (file)
@@ -111,9 +111,7 @@ static char *mips_regmask_frag;
 extern int target_big_endian;
 
 /* The name of the readonly data section.  */
-#define RDATA_SECTION_NAME (OUTPUT_FLAVOR == bfd_target_aout_flavour \
-                           ? ".data" \
-                           : OUTPUT_FLAVOR == bfd_target_ecoff_flavour \
+#define RDATA_SECTION_NAME (OUTPUT_FLAVOR == bfd_target_ecoff_flavour \
                            ? ".rdata" \
                            : OUTPUT_FLAVOR == bfd_target_coff_flavour \
                            ? ".rdata" \
@@ -281,13 +279,14 @@ static int mips_32bitmode = 0;
 
 #define HAVE_64BIT_OBJECTS (mips_abi == N64_ABI)
 
-/* We can only have 64bit addresses if the object file format
-   supports it.  */
+/* True if relocations are stored in-place.  */
+#define HAVE_IN_PLACE_ADDENDS (!HAVE_NEWABI)
+
+/* We can only have 64bit addresses if the object file format supports it.  */
 #define HAVE_32BIT_ADDRESSES                           \
    (HAVE_32BIT_GPRS                                    \
-    || ((bfd_arch_bits_per_address (stdoutput) == 32   \
-         || ! HAVE_64BIT_OBJECTS)                      \
-        && mips_pic != EMBEDDED_PIC))
+    || (bfd_arch_bits_per_address (stdoutput) == 32    \
+        || ! HAVE_64BIT_OBJECTS))                      \
 
 #define HAVE_64BIT_ADDRESSES (! HAVE_32BIT_ADDRESSES)
 
@@ -325,15 +324,29 @@ static int mips_32bitmode = 0;
 /* True if CPU has a ror instruction.  */
 #define CPU_HAS_ROR(CPU)       CPU_HAS_DROR (CPU)
 
-/* Whether the processor uses hardware interlocks to protect
-   reads from the HI and LO registers, and thus does not
-   require nops to be inserted.  */
-
-#define hilo_interlocks (mips_opts.arch == CPU_R4010                       \
-                         || mips_opts.arch == CPU_VR5500                   \
-                         || mips_opts.arch == CPU_RM7000                   \
-                         || mips_opts.arch == CPU_SB1                      \
-                         )
+/* True if mflo and mfhi can be immediately followed by instructions
+   which write to the HI and LO registers.
+
+   According to MIPS specifications, MIPS ISAs I, II, and III need
+   (at least) two instructions between the reads of HI/LO and
+   instructions which write them, and later ISAs do not.  Contradicting
+   the MIPS specifications, some MIPS IV processor user manuals (e.g.
+   the UM for the NEC Vr5000) document needing the instructions between
+   HI/LO reads and writes, as well.  Therefore, we declare only MIPS32,
+   MIPS64 and later ISAs to have the interlocks, plus any specific
+   earlier-ISA CPUs for which CPU documentation declares that the
+   instructions are really interlocked.  */
+#define hilo_interlocks \
+  (mips_opts.isa == ISA_MIPS32                        \
+   || mips_opts.isa == ISA_MIPS32R2                   \
+   || mips_opts.isa == ISA_MIPS64                     \
+   || mips_opts.isa == ISA_MIPS64R2                   \
+   || mips_opts.arch == CPU_R4010                     \
+   || mips_opts.arch == CPU_R10000                    \
+   || mips_opts.arch == CPU_R12000                    \
+   || mips_opts.arch == CPU_RM7000                    \
+   || mips_opts.arch == CPU_VR5500                    \
+   )
 
 /* Whether the processor uses hardware interlocks to protect reads
    from the GPRs after they are loaded from memory, and thus does not
@@ -342,8 +355,6 @@ static int mips_32bitmode = 0;
    level I.  */
 #define gpr_interlocks \
   (mips_opts.isa != ISA_MIPS1  \
-   || mips_opts.arch == CPU_VR5400  \
-   || mips_opts.arch == CPU_VR5500  \
    || mips_opts.arch == CPU_R3900)
 
 /* Whether the processor uses hardware interlocks to avoid delays
@@ -359,9 +370,6 @@ static int mips_32bitmode = 0;
     && mips_opts.isa != ISA_MIPS2                     \
     && mips_opts.isa != ISA_MIPS3)                    \
    || mips_opts.arch == CPU_R4300                     \
-   || mips_opts.arch == CPU_VR5400                    \
-   || mips_opts.arch == CPU_VR5500                    \
-   || mips_opts.arch == CPU_SB1                       \
    )
 
 /* Whether the processor uses hardware interlocks to protect reads
@@ -607,7 +615,7 @@ static const unsigned int mips16_to_32_reg_map[] =
   16, 17, 2, 3, 4, 5, 6, 7
 };
 
-static int mips_fix_4122_bugs;
+static int mips_fix_vr4120;
 
 /* We don't relax branches by default, since this causes us to expand
    `la .l2 - .l1' if there's a branch between .l1 and .l2, because we
@@ -616,81 +624,61 @@ static int mips_fix_4122_bugs;
 
 static int mips_relax_branch;
 \f
-/* Since the MIPS does not have multiple forms of PC relative
-   instructions, we do not have to do relaxing as is done on other
-   platforms.  However, we do have to handle GP relative addressing
-   correctly, which turns out to be a similar problem.
-
-   Every macro that refers to a symbol can occur in (at least) two
-   forms, one with GP relative addressing and one without.  For
-   example, loading a global variable into a register generally uses
-   a macro instruction like this:
-     lw $4,i
-   If i can be addressed off the GP register (this is true if it is in
-   the .sbss or .sdata section, or if it is known to be smaller than
-   the -G argument) this will generate the following instruction:
-     lw $4,i($gp)
-   This instruction will use a GPREL reloc.  If i can not be addressed
-   off the GP register, the following instruction sequence will be used:
-     lui $at,i
-     lw $4,i($at)
-   In this case the first instruction will have a HI16 reloc, and the
-   second reloc will have a LO16 reloc.  Both relocs will be against
-   the symbol i.
-
-   The issue here is that we may not know whether i is GP addressable
-   until after we see the instruction that uses it.  Therefore, we
-   want to be able to choose the final instruction sequence only at
-   the end of the assembly.  This is similar to the way other
-   platforms choose the size of a PC relative instruction only at the
-   end of assembly.
-
-   When generating position independent code we do not use GP
-   addressing in quite the same way, but the issue still arises as
-   external symbols and local symbols must be handled differently.
-
-   We handle these issues by actually generating both possible
-   instruction sequences.  The longer one is put in a frag_var with
-   type rs_machine_dependent.  We encode what to do with the frag in
-   the subtype field.  We encode (1) the number of existing bytes to
-   replace, (2) the number of new bytes to use, (3) the offset from
-   the start of the existing bytes to the first reloc we must generate
-   (that is, the offset is applied from the start of the existing
-   bytes after they are replaced by the new bytes, if any), (4) the
-   offset from the start of the existing bytes to the second reloc,
-   (5) whether a third reloc is needed (the third reloc is always four
-   bytes after the second reloc), and (6) whether to warn if this
-   variant is used (this is sometimes needed if .set nomacro or .set
-   noat is in effect).  All these numbers are reasonably small.
-
-   Generating two instruction sequences must be handled carefully to
-   ensure that delay slots are handled correctly.  Fortunately, there
-   are a limited number of cases.  When the second instruction
-   sequence is generated, append_insn is directed to maintain the
-   existing delay slot information, so it continues to apply to any
-   code after the second instruction sequence.  This means that the
-   second instruction sequence must not impose any requirements not
-   required by the first instruction sequence.
-
-   These variant frags are then handled in functions called by the
-   machine independent code.  md_estimate_size_before_relax returns
-   the final size of the frag.  md_convert_frag sets up the final form
-   of the frag.  tc_gen_reloc adjust the first reloc and adds a second
-   one if needed.  */
-#define RELAX_ENCODE(old, new, reloc1, reloc2, reloc3, warn) \
-  ((relax_substateT) \
-   (((old) << 23) \
-    | ((new) << 16) \
-    | (((reloc1) + 64) << 9) \
-    | (((reloc2) + 64) << 2) \
-    | ((reloc3) ? (1 << 1) : 0) \
-    | ((warn) ? 1 : 0)))
-#define RELAX_OLD(i) (((i) >> 23) & 0x7f)
-#define RELAX_NEW(i) (((i) >> 16) & 0x7f)
-#define RELAX_RELOC1(i) ((valueT) (((i) >> 9) & 0x7f) - 64)
-#define RELAX_RELOC2(i) ((valueT) (((i) >> 2) & 0x7f) - 64)
-#define RELAX_RELOC3(i) (((i) >> 1) & 1)
-#define RELAX_WARN(i) ((i) & 1)
+/* The expansion of many macros depends on the type of symbol that
+   they refer to.  For example, when generating position-dependent code,
+   a macro that refers to a symbol may have two different expansions,
+   one which uses GP-relative addresses and one which uses absolute
+   addresses.  When generating SVR4-style PIC, a macro may have
+   different expansions for local and global symbols.
+
+   We handle these situations by generating both sequences and putting
+   them in variant frags.  In position-dependent code, the first sequence
+   will be the GP-relative one and the second sequence will be the
+   absolute one.  In SVR4 PIC, the first sequence will be for global
+   symbols and the second will be for local symbols.
+
+   The frag's "subtype" is RELAX_ENCODE (FIRST, SECOND), where FIRST and
+   SECOND are the lengths of the two sequences in bytes.  These fields
+   can be extracted using RELAX_FIRST() and RELAX_SECOND().  In addition,
+   the subtype has the following flags:
+
+   RELAX_USE_SECOND
+       Set if it has been decided that we should use the second
+       sequence instead of the first.
+
+   RELAX_SECOND_LONGER
+       Set in the first variant frag if the macro's second implementation
+       is longer than its first.  This refers to the macro as a whole,
+       not an individual relaxation.
+
+   RELAX_NOMACRO
+       Set in the first variant frag if the macro appeared in a .set nomacro
+       block and if one alternative requires a warning but the other does not.
+
+   RELAX_DELAY_SLOT
+       Like RELAX_NOMACRO, but indicates that the macro appears in a branch
+       delay slot.
+
+   The frag's "opcode" points to the first fixup for relaxable code.
+
+   Relaxable macros are generated using a sequence such as:
+
+      relax_start (SYMBOL);
+      ... generate first expansion ...
+      relax_switch ();
+      ... generate second expansion ...
+      relax_end ();
+
+   The code and fixups for the unwanted alternative are discarded
+   by md_convert_frag.  */
+#define RELAX_ENCODE(FIRST, SECOND) (((FIRST) << 8) | (SECOND))
+
+#define RELAX_FIRST(X) (((X) >> 8) & 0xff)
+#define RELAX_SECOND(X) ((X) & 0xff)
+#define RELAX_USE_SECOND 0x10000
+#define RELAX_SECOND_LONGER 0x20000
+#define RELAX_NOMACRO 0x40000
+#define RELAX_DELAY_SLOT 0x80000
 
 /* Branch without likely bit.  If label is out of range, we turn:
 
@@ -822,6 +810,42 @@ static int mips_relax_branch;
   (((x) &~ (offsetT) 0x7fff) == 0                                      \
    || (((x) &~ (offsetT) 0x7fff) == ~ (offsetT) 0x7fff))
 
+\f
+/* Global variables used when generating relaxable macros.  See the
+   comment above RELAX_ENCODE for more details about how relaxation
+   is used.  */
+static struct {
+  /* 0 if we're not emitting a relaxable macro.
+     1 if we're emitting the first of the two relaxation alternatives.
+     2 if we're emitting the second alternative.  */
+  int sequence;
+
+  /* The first relaxable fixup in the current frag.  (In other words,
+     the first fixup that refers to relaxable code.)  */
+  fixS *first_fixup;
+
+  /* sizes[0] says how many bytes of the first alternative are stored in
+     the current frag.  Likewise sizes[1] for the second alternative.  */
+  unsigned int sizes[2];
+
+  /* The symbol on which the choice of sequence depends.  */
+  symbolS *symbol;
+} mips_relax;
+\f
+/* Global variables used to decide whether a macro needs a warning.  */
+static struct {
+  /* True if the macro is in a branch delay slot.  */
+  bfd_boolean delay_slot_p;
+
+  /* For relaxable macros, sizes[0] is the length of the first alternative
+     in bytes and sizes[1] is the length of the second alternative.
+     For non-relaxable macros, both elements give the length of the
+     macro in bytes.  */
+  unsigned int sizes[2];
+
+  /* The first variant frag for this macro.  */
+  fragS *first_frag;
+} mips_macro_warning;
 \f
 /* Prototypes for static functions.  */
 
@@ -831,12 +855,13 @@ static int mips_relax_branch;
 enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
 
 static void append_insn
-  (char *place, struct mips_cl_insn *ip, expressionS *p,
-   bfd_reloc_code_real_type *r);
+  (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type *r);
 static void mips_no_prev_insn (int);
 static void mips16_macro_build
-  (char *, int *, expressionS *, const char *, const char *, va_list);
-static void load_register (int *, int, expressionS *, int);
+  (expressionS *, const char *, const char *, va_list);
+static void load_register (int, expressionS *, int);
+static void macro_start (void);
+static void macro_end (void);
 static void macro (struct mips_cl_insn * ip);
 static void mips16_macro (struct mips_cl_insn * ip);
 #ifdef LOSING_COMPILER
@@ -1057,8 +1082,6 @@ mips_target_format (void)
 {
   switch (OUTPUT_FLAVOR)
     {
-    case bfd_target_aout_flavour:
-      return target_big_endian ? "a.out-mips-big" : "a.out-mips-little";
     case bfd_target_ecoff_flavour:
       return target_big_endian ? "ecoff-bigmips" : ECOFF_LITTLE_FORMAT;
     case bfd_target_coff_flavour:
@@ -1215,8 +1238,7 @@ md_begin (void)
   /* set the default alignment for the text section (2**2) */
   record_alignment (text_section, 2);
 
-  if (USE_GLOBAL_POINTER_OPT)
-    bfd_set_gp_size (stdoutput, g_switch_value);
+  bfd_set_gp_size (stdoutput, g_switch_value);
 
   if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
     {
@@ -1354,19 +1376,21 @@ md_assemble (char *str)
 
   if (insn.insn_mo->pinfo == INSN_MACRO)
     {
+      macro_start ();
       if (mips_opts.mips16)
        mips16_macro (&insn);
       else
        macro (&insn);
+      macro_end ();
     }
   else
     {
       if (imm_expr.X_op != O_absent)
-       append_insn (NULL, &insn, &imm_expr, imm_reloc);
+       append_insn (&insn, &imm_expr, imm_reloc);
       else if (offset_expr.X_op != O_absent)
-       append_insn (NULL, &insn, &offset_expr, offset_reloc);
+       append_insn (&insn, &offset_expr, offset_reloc);
       else
-       append_insn (NULL, &insn, NULL, unused_reloc);
+       append_insn (&insn, NULL, unused_reloc);
     }
 }
 
@@ -1377,8 +1401,9 @@ md_assemble (char *str)
 static inline bfd_boolean
 reloc_needs_lo_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_HI16_S
-         || reloc == BFD_RELOC_MIPS_GOT16);
+  return (HAVE_IN_PLACE_ADDENDS
+         && (reloc == BFD_RELOC_HI16_S
+             || reloc == BFD_RELOC_MIPS_GOT16));
 }
 
 /* Return true if the given fixup is followed by a matching R_MIPS_LO16
@@ -1526,19 +1551,66 @@ mips16_mark_labels (void)
     }
 }
 
-/* Output an instruction.  PLACE is where to put the instruction; if
-   it is NULL, this uses frag_more to get room.  IP is the instruction
-   information.  ADDRESS_EXPR is an operand of the instruction to be
-   used with RELOC_TYPE.  */
+/* End the current frag.  Make it a variant frag and record the
+   relaxation info.  */
+
+static void
+relax_close_frag (void)
+{
+  mips_macro_warning.first_frag = frag_now;
+  frag_var (rs_machine_dependent, 0, 0,
+           RELAX_ENCODE (mips_relax.sizes[0], mips_relax.sizes[1]),
+           mips_relax.symbol, 0, (char *) mips_relax.first_fixup);
+
+  memset (&mips_relax.sizes, 0, sizeof (mips_relax.sizes));
+  mips_relax.first_fixup = 0;
+}
+
+/* Start a new relaxation sequence whose expansion depends on SYMBOL.
+   See the comment above RELAX_ENCODE for more details.  */
+
+static void
+relax_start (symbolS *symbol)
+{
+  assert (mips_relax.sequence == 0);
+  mips_relax.sequence = 1;
+  mips_relax.symbol = symbol;
+}
+
+/* Start generating the second version of a relaxable sequence.
+   See the comment above RELAX_ENCODE for more details.  */
+
+static void
+relax_switch (void)
+{
+  assert (mips_relax.sequence == 1);
+  mips_relax.sequence = 2;
+}
+
+/* End the current relaxable sequence.  */
 
 static void
-append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
+relax_end (void)
+{
+  assert (mips_relax.sequence == 2);
+  relax_close_frag ();
+  mips_relax.sequence = 0;
+}
+
+/* Output an instruction.  IP is the instruction information.
+   ADDRESS_EXPR is an operand of the instruction to be used with
+   RELOC_TYPE.  */
+
+static void
+append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
             bfd_reloc_code_real_type *reloc_type)
 {
   register unsigned long prev_pinfo, pinfo;
   char *f;
   fixS *fixp[3];
   int nops = 0;
+  relax_stateT prev_insn_frag_type = 0;
+  bfd_boolean relaxed_branch = FALSE;
   bfd_boolean force_new_frag = FALSE;
 
   /* Mark instruction labels in mips16 mode.  */
@@ -1547,7 +1619,8 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
   prev_pinfo = prev_insn.insn_mo->pinfo;
   pinfo = ip->insn_mo->pinfo;
 
-  if (place == NULL && (! mips_opts.noreorder || prev_nop_frag != NULL))
+  if (mips_relax.sequence != 2
+      && (!mips_opts.noreorder || prev_nop_frag != NULL))
     {
       int prev_prev_nop;
 
@@ -1706,7 +1779,7 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
              though the tx39's divide insns still do require the
             delay.  */
          if (! (hilo_interlocks
-                || (mips_tune == CPU_R3900 && (pinfo & INSN_MULT)))
+                || (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT)))
              && (mips_optimize == 0
                  || (pinfo & INSN_WRITE_LO)))
            nops += 2;
@@ -1728,7 +1801,7 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
             insert a NOP.  Some newer processors have interlocks.
             Also the note tx39's multiply above.  */
          if (! (hilo_interlocks
-                || (mips_tune == CPU_R3900 && (pinfo & INSN_MULT)))
+                || (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT)))
              && (mips_optimize == 0
                  || (pinfo & INSN_WRITE_HI)))
            nops += 2;
@@ -1766,11 +1839,11 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
          || ((prev_prev_insn.insn_mo->pinfo & INSN_READ_LO)
              && (pinfo & INSN_WRITE_LO)
              && ! (hilo_interlocks
-                   || (mips_tune == CPU_R3900 && (pinfo & INSN_MULT))))
+                   || (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT))))
          || ((prev_prev_insn.insn_mo->pinfo & INSN_READ_HI)
              && (pinfo & INSN_WRITE_HI)
              && ! (hilo_interlocks
-                   || (mips_tune == CPU_R3900 && (pinfo & INSN_MULT)))))
+                   || (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT)))))
        prev_prev_nop = 1;
       else
        prev_prev_nop = 0;
@@ -1781,46 +1854,57 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
       if (prev_prev_nop && nops == 0)
        ++nops;
 
-      if (mips_fix_4122_bugs && prev_insn.insn_mo->name)
+      if (mips_fix_vr4120 && prev_insn.insn_mo->name)
        {
          /* We're out of bits in pinfo, so we must resort to string
             ops here.  Shortcuts are selected based on opcodes being
-            limited to the VR4122 instruction set.  */
+            limited to the VR4120 instruction set.  */
          int min_nops = 0;
          const char *pn = prev_insn.insn_mo->name;
          const char *tn = ip->insn_mo->name;
-         if (strncmp(pn, "macc", 4) == 0
-             || strncmp(pn, "dmacc", 5) == 0)
+         if (strncmp (pn, "macc", 4) == 0
+             || strncmp (pn, "dmacc", 5) == 0)
            {
              /* Errata 21 - [D]DIV[U] after [D]MACC */
              if (strstr (tn, "div"))
-               {
-                 min_nops = 1;
-               }
+               min_nops = 1;
 
-             /* Errata 23 - Continuous DMULT[U]/DMACC instructions */
-             if (pn[0] == 'd' /* dmacc */
-                 && (strncmp(tn, "dmult", 5) == 0
-                     || strncmp(tn, "dmacc", 5) == 0))
-               {
-                 min_nops = 1;
-               }
+             /* VR4181A errata MD(1): "If a MULT, MULTU, DMULT or DMULTU
+                instruction is executed immediately after a MACC or
+                DMACC instruction, the result of [either instruction]
+                is incorrect."  */
+             if (strncmp (tn, "mult", 4) == 0
+                 || strncmp (tn, "dmult", 5) == 0)
+               min_nops = 1;
+
+             /* Errata 23 - Continuous DMULT[U]/DMACC instructions.
+                Applies on top of VR4181A MD(1) errata.  */
+             if (pn[0] == 'd' && strncmp (tn, "dmacc", 5) == 0)
+               min_nops = 1;
 
              /* Errata 24 - MT{LO,HI} after [D]MACC */
              if (strcmp (tn, "mtlo") == 0
                  || strcmp (tn, "mthi") == 0)
-               {
-                 min_nops = 1;
-               }
-
+               min_nops = 1;
            }
-         else if (strncmp(pn, "dmult", 5) == 0
-                  && (strncmp(tn, "dmult", 5) == 0
-                      || strncmp(tn, "dmacc", 5) == 0))
+         else if (strncmp (pn, "dmult", 5) == 0
+                  && (strncmp (tn, "dmult", 5) == 0
+                      || strncmp (tn, "dmacc", 5) == 0))
            {
              /* Here is the rest of errata 23.  */
              min_nops = 1;
            }
+         else if ((strncmp (pn, "dmult", 5) == 0 || strstr (pn, "div"))
+                  && (strncmp (tn, "macc", 4) == 0
+                      || strncmp (tn, "dmacc", 5) == 0))
+           {
+             /* VR4181A errata MD(4): "If a MACC or DMACC instruction is
+                executed immediately after a DMULT, DMULTU, DIV, DIVU,
+                DDIV or DDIVU instruction, the result of the MACC or
+                DMACC instruction is incorrect.".  This partly overlaps
+                the workaround for errata 23.  */
+             min_nops = 1;
+           }
          if (nops < min_nops)
            nops = min_nops;
        }
@@ -1919,8 +2003,11 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
        }
     }
 
-  if (place == NULL
-      && address_expr
+  /* Record the frag type before frag_var.  */
+  if (prev_insn_frag)
+    prev_insn_frag_type = prev_insn_frag->fr_type;
+
+  if (address_expr
       && *reloc_type == BFD_RELOC_16_PCREL_S2
       && (pinfo & INSN_UNCOND_BRANCH_DELAY || pinfo & INSN_COND_BRANCH_DELAY
          || pinfo & INSN_COND_BRANCH_LIKELY)
@@ -1932,6 +2019,7 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
       && !(mips_opts.noat && mips_pic != NO_PIC)
       && !mips_opts.mips16)
     {
+      relaxed_branch = TRUE;
       f = frag_var (rs_machine_dependent,
                    relaxed_branch_length
                    (NULL, NULL,
@@ -1960,8 +2048,6 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
                                          == BFD_RELOC_MIPS16_JMP)),
                    make_expr_symbol (address_expr), 0, NULL);
     }
-  else if (place != NULL)
-    f = place;
   else if (mips_opts.mips16
           && ! ip->use_extend
           && *reloc_type != BFD_RELOC_MIPS16_JMP)
@@ -1978,11 +2064,26 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
          && (prev_pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
        as_warn (_("extended instruction in delay slot"));
 
+      if (mips_relax.sequence)
+       {
+         /* If we've reached the end of this frag, turn it into a variant
+            frag and record the information for the instructions we've
+            written so far.  */
+         if (frag_room () < 4)
+           relax_close_frag ();
+         mips_relax.sizes[mips_relax.sequence - 1] += 4;
+       }
+
+      if (mips_relax.sequence != 2)
+       mips_macro_warning.sizes[0] += 4;
+      if (mips_relax.sequence != 1)
+       mips_macro_warning.sizes[1] += 4;
+
       f = frag_more (4);
     }
 
   fixp[0] = fixp[1] = fixp[2] = NULL;
-  if (address_expr != NULL && *reloc_type < BFD_RELOC_UNUSED)
+  if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED)
     {
       if (address_expr->X_op == O_constant)
        {
@@ -2015,6 +2116,7 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
              ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
              break;
 
+           case BFD_RELOC_UNUSED:
            case BFD_RELOC_LO16:
            case BFD_RELOC_MIPS_GOT_DISP:
              ip->insn_opcode |= address_expr->X_add_number & 0xffff;
@@ -2050,85 +2152,86 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
              internalError ();
            }
        }
-      else
-       {
+      else if (*reloc_type < BFD_RELOC_UNUSED)
        need_reloc:
-         /* Don't generate a reloc if we are writing into a variant frag.  */
-         if (place == NULL)
-           {
-             reloc_howto_type *howto;
-             int i;
+       {
+         reloc_howto_type *howto;
+         int i;
 
-             /* In a compound relocation, it is the final (outermost)
-                operator that determines the relocated field.  */
-             for (i = 1; i < 3; i++)
-               if (reloc_type[i] == BFD_RELOC_UNUSED)
-                 break;
+         /* In a compound relocation, it is the final (outermost)
+            operator that determines the relocated field.  */
+         for (i = 1; i < 3; i++)
+           if (reloc_type[i] == BFD_RELOC_UNUSED)
+             break;
 
-             howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
-             fixp[0] = fix_new_exp (frag_now, f - frag_now->fr_literal,
-                                    bfd_get_reloc_size(howto),
-                                    address_expr,
-                                    reloc_type[0] == BFD_RELOC_16_PCREL_S2,
-                                    reloc_type[0]);
-
-             /* These relocations can have an addend that won't fit in
-                4 octets for 64bit assembly.  */
-             if (HAVE_64BIT_GPRS
-                 && ! howto->partial_inplace
-                 && (reloc_type[0] == BFD_RELOC_16
-                     || reloc_type[0] == BFD_RELOC_32
-                     || reloc_type[0] == BFD_RELOC_MIPS_JMP
-                     || reloc_type[0] == BFD_RELOC_HI16_S
-                     || reloc_type[0] == BFD_RELOC_LO16
-                     || reloc_type[0] == BFD_RELOC_GPREL16
-                     || reloc_type[0] == BFD_RELOC_MIPS_LITERAL
-                     || reloc_type[0] == BFD_RELOC_GPREL32
-                     || reloc_type[0] == BFD_RELOC_64
-                     || reloc_type[0] == BFD_RELOC_CTOR
-                     || reloc_type[0] == BFD_RELOC_MIPS_SUB
-                     || reloc_type[0] == BFD_RELOC_MIPS_HIGHEST
-                     || reloc_type[0] == BFD_RELOC_MIPS_HIGHER
-                     || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP
-                     || reloc_type[0] == BFD_RELOC_MIPS_REL16
-                     || reloc_type[0] == BFD_RELOC_MIPS_RELGOT))
-               fixp[0]->fx_no_overflow = 1;
-
-             if (reloc_needs_lo_p (*reloc_type))
-               {
-                 struct mips_hi_fixup *hi_fixup;
+         howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
+         fixp[0] = fix_new_exp (frag_now, f - frag_now->fr_literal,
+                                bfd_get_reloc_size(howto),
+                                address_expr,
+                                reloc_type[0] == BFD_RELOC_16_PCREL_S2,
+                                reloc_type[0]);
+
+         /* These relocations can have an addend that won't fit in
+            4 octets for 64bit assembly.  */
+         if (HAVE_64BIT_GPRS
+             && ! howto->partial_inplace
+             && (reloc_type[0] == BFD_RELOC_16
+                 || reloc_type[0] == BFD_RELOC_32
+                 || reloc_type[0] == BFD_RELOC_MIPS_JMP
+                 || reloc_type[0] == BFD_RELOC_HI16_S
+                 || reloc_type[0] == BFD_RELOC_LO16
+                 || reloc_type[0] == BFD_RELOC_GPREL16
+                 || reloc_type[0] == BFD_RELOC_MIPS_LITERAL
+                 || reloc_type[0] == BFD_RELOC_GPREL32
+                 || reloc_type[0] == BFD_RELOC_64
+                 || reloc_type[0] == BFD_RELOC_CTOR
+                 || reloc_type[0] == BFD_RELOC_MIPS_SUB
+                 || reloc_type[0] == BFD_RELOC_MIPS_HIGHEST
+                 || reloc_type[0] == BFD_RELOC_MIPS_HIGHER
+                 || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP
+                 || reloc_type[0] == BFD_RELOC_MIPS_REL16
+                 || reloc_type[0] == BFD_RELOC_MIPS_RELGOT))
+           fixp[0]->fx_no_overflow = 1;
+
+         if (mips_relax.sequence)
+           {
+             if (mips_relax.first_fixup == 0)
+               mips_relax.first_fixup = fixp[0];
+           }
+         else if (reloc_needs_lo_p (*reloc_type))
+           {
+             struct mips_hi_fixup *hi_fixup;
 
-                 /* Reuse the last entry if it already has a matching %lo.  */
-                 hi_fixup = mips_hi_fixup_list;
-                 if (hi_fixup == 0
-                     || !fixup_has_matching_lo_p (hi_fixup->fixp))
-                   {
-                     hi_fixup = ((struct mips_hi_fixup *)
-                                 xmalloc (sizeof (struct mips_hi_fixup)));
-                     hi_fixup->next = mips_hi_fixup_list;
-                     mips_hi_fixup_list = hi_fixup;
-                   }
-                 hi_fixup->fixp = fixp[0];
-                 hi_fixup->seg = now_seg;
+             /* Reuse the last entry if it already has a matching %lo.  */
+             hi_fixup = mips_hi_fixup_list;
+             if (hi_fixup == 0
+                 || !fixup_has_matching_lo_p (hi_fixup->fixp))
+               {
+                 hi_fixup = ((struct mips_hi_fixup *)
+                             xmalloc (sizeof (struct mips_hi_fixup)));
+                 hi_fixup->next = mips_hi_fixup_list;
+                 mips_hi_fixup_list = hi_fixup;
                }
+             hi_fixup->fixp = fixp[0];
+             hi_fixup->seg = now_seg;
+           }
 
-             /* Add fixups for the second and third relocations, if given.
-                Note that the ABI allows the second relocation to be
-                against RSS_UNDEF, RSS_GP, RSS_GP0 or RSS_LOC.  At the
-                moment we only use RSS_UNDEF, but we could add support
-                for the others if it ever becomes necessary.  */
-             for (i = 1; i < 3; i++)
-               if (reloc_type[i] != BFD_RELOC_UNUSED)
-                 {
-                   address_expr->X_op = O_absent;
-                   address_expr->X_add_symbol = 0;
-                   address_expr->X_add_number = 0;
+         /* Add fixups for the second and third relocations, if given.
+            Note that the ABI allows the second relocation to be
+            against RSS_UNDEF, RSS_GP, RSS_GP0 or RSS_LOC.  At the
+            moment we only use RSS_UNDEF, but we could add support
+            for the others if it ever becomes necessary.  */
+         for (i = 1; i < 3; i++)
+           if (reloc_type[i] != BFD_RELOC_UNUSED)
+             {
+               address_expr->X_op = O_absent;
+               address_expr->X_add_symbol = 0;
+               address_expr->X_add_number = 0;
 
-                   fixp[i] = fix_new_exp (frag_now, fixp[0]->fx_where,
-                                          fixp[0]->fx_size, address_expr,
-                                          FALSE, reloc_type[i]);
-                 }
-           }
+               fixp[i] = fix_new_exp (frag_now, fixp[0]->fx_where,
+                                      fixp[0]->fx_size, address_expr,
+                                      FALSE, reloc_type[i]);
+             }
        }
     }
 
@@ -2144,7 +2247,12 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
       md_number_to_chars (f, ip->insn_opcode >> 16, 2);
       md_number_to_chars (f + 2, ip->insn_opcode & 0xffff, 2);
 #ifdef OBJ_ELF
-      dwarf2_emit_insn (4);
+      /* The value passed to dwarf2_emit_insn is the distance between
+        the end of the current instruction and the address that should
+        be recorded in the debug tables.  Since we want to use ISA-encoded
+        addresses in MIPS16 debug info, the value is one byte less than
+        the real instruction length.  */
+      dwarf2_emit_insn (3);
 #endif
     }
   else
@@ -2156,7 +2264,7 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
        }
       md_number_to_chars (f, ip->insn_opcode, 2);
 #ifdef OBJ_ELF
-      dwarf2_emit_insn (ip->use_extend ? 4 : 2);
+      dwarf2_emit_insn (ip->use_extend ? 3 : 1);
 #endif
     }
 
@@ -2216,7 +2324,7 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
                              & MIPS16OP_MASK_REGR32);
     }
 
-  if (place == NULL && ! mips_opts.noreorder)
+  if (mips_relax.sequence != 2 && !mips_opts.noreorder)
     {
       /* Filling the branch delay slot is more complex.  We try to
         switch the branch with the previous instruction, which we can
@@ -2262,12 +2370,12 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
                 there are any branches to anything other than a
                 label, users must use .set noreorder.  */
              || insn_labels != NULL
-             /* If the previous instruction is in a variant frag, we
-                can not do the swap.  This does not apply to the
-                mips16, which uses variant frags for different
-                purposes.  */
+             /* If the previous instruction is in a variant frag
+                other than this branch's one, we cannot do the swap.
+                This does not apply to the mips16, which uses variant
+                frags for different purposes.  */
              || (! mips_opts.mips16
-                 && prev_insn_frag->fr_type == rs_machine_dependent)
+                 && prev_insn_frag_type == rs_machine_dependent)
              /* If the branch reads the condition codes, we don't
                 even try to swap, because in the sequence
                   ctc1 $X,$31
@@ -2290,7 +2398,7 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
                         | INSN_WRITE_COND_CODE))
                  && ! cop_interlocks)
              || (! (hilo_interlocks
-                    || (mips_tune == CPU_R3900 && (pinfo & INSN_MULT)))
+                    || (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT)))
                  && (prev_pinfo
                      & (INSN_READ_LO
                         | INSN_READ_HI)))
@@ -2394,11 +2502,6 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
              || (mips_opts.mips16
                  && (pinfo & MIPS16_INSN_WRITE_31)
                  && insn_uses_reg (&prev_insn, RA, MIPS_GR_REG))
-             /* If we are generating embedded PIC code, the branch
-                might be expanded into a sequence which uses $at, so
-                we can't swap with an instruction which reads it.  */
-             || (mips_pic == EMBEDDED_PIC
-                 && insn_uses_reg (&prev_insn, AT, MIPS_GR_REG))
              /* If the previous previous instruction has a load
                 delay, and sets a register that the branch reads, we
                 can not swap.  */
@@ -2452,9 +2555,29 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
                  char temp[4];
 
                  prev_f = prev_insn_frag->fr_literal + prev_insn_where;
-                 memcpy (temp, prev_f, 4);
-                 memcpy (prev_f, f, 4);
-                 memcpy (f, temp, 4);
+                 if (!relaxed_branch)
+                   {
+                     /* If this is not a relaxed branch, then just
+                        swap the instructions.  */
+                     memcpy (temp, prev_f, 4);
+                     memcpy (prev_f, f, 4);
+                     memcpy (f, temp, 4);
+                   }
+                 else
+                   {
+                     /* If this is a relaxed branch, then we move the
+                        instruction to be placed in the delay slot to
+                        the current frag, shrinking the fixed part of
+                        the originating frag.  If the branch occupies
+                        the tail of the latter, we move it backwards,
+                        into the space freed by the moved instruction.  */
+                     f = frag_more (4);
+                     memcpy (f, prev_f, 4);
+                     prev_insn_frag->fr_fix -= 4;
+                     if (prev_insn_frag->fr_type == rs_machine_dependent)
+                       memmove (prev_f, prev_f + 4, prev_insn_frag->fr_var);
+                   }
+
                  if (prev_insn_fixp[0])
                    {
                      prev_insn_fixp[0]->fx_frag = frag_now;
@@ -2482,20 +2605,33 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
                         frag.  */
                      force_new_frag = TRUE;
                    }
-                 if (fixp[0])
+
+                 if (!relaxed_branch)
                    {
-                     fixp[0]->fx_frag = prev_insn_frag;
-                     fixp[0]->fx_where = prev_insn_where;
+                     if (fixp[0])
+                       {
+                         fixp[0]->fx_frag = prev_insn_frag;
+                         fixp[0]->fx_where = prev_insn_where;
+                       }
+                     if (fixp[1])
+                       {
+                         fixp[1]->fx_frag = prev_insn_frag;
+                         fixp[1]->fx_where = prev_insn_where;
+                       }
+                     if (fixp[2])
+                       {
+                         fixp[2]->fx_frag = prev_insn_frag;
+                         fixp[2]->fx_where = prev_insn_where;
+                       }
                    }
-                 if (fixp[1])
+                 else if (prev_insn_frag->fr_type == rs_machine_dependent)
                    {
-                     fixp[1]->fx_frag = prev_insn_frag;
-                     fixp[1]->fx_where = prev_insn_where;
-                   }
-                 if (fixp[2])
-                   {
-                     fixp[2]->fx_frag = prev_insn_frag;
-                     fixp[2]->fx_where = prev_insn_where;
+                     if (fixp[0])
+                       fixp[0]->fx_where -= 4;
+                     if (fixp[1])
+                       fixp[1]->fx_where -= 4;
+                     if (fixp[2])
+                       fixp[2]->fx_where -= 4;
                    }
                }
              else
@@ -2575,6 +2711,7 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
          prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
          prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
          prev_insn_extended = 0;
+         prev_insn_is_delay_slot = 1;
        }
       else
        {
@@ -2607,7 +2744,7 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
       prev_insn_where = f - frag_now->fr_literal;
       prev_insn_valid = 1;
     }
-  else if (place == NULL)
+  else if (mips_relax.sequence != 2)
     {
       /* We need to record a bit of information even when we are not
          reordering, in order to determine the base address for mips16
@@ -2623,15 +2760,6 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr,
 
   /* We just output an insn, so the next one doesn't have a label.  */
   mips_clear_insn_labels ();
-
-  /* We must ensure that the frag to which an instruction that was
-     moved from a non-variant frag doesn't become a variant frag,
-     otherwise tc_gen_reloc may get confused.  */
-  if (force_new_frag)
-    {
-      frag_wane (frag_now);
-      frag_new (0);
-    }
 }
 
 /* This function forgets that there was any previous instruction or
@@ -2717,16 +2845,15 @@ mips_emit_delays (bfd_boolean insns)
            ++nops;
        }
 
-      if (mips_fix_4122_bugs && prev_insn.insn_mo->name)
+      if (mips_fix_vr4120 && prev_insn.insn_mo->name)
        {
          int min_nops = 0;
          const char *pn = prev_insn.insn_mo->name;
-         if (strncmp(pn, "macc", 4) == 0
-             || strncmp(pn, "dmacc", 5) == 0
-             || strncmp(pn, "dmult", 5) == 0)
-           {
-             min_nops = 1;
-           }
+         if (strncmp (pn, "macc", 4) == 0
+             || strncmp (pn, "dmacc", 5) == 0
+             || strncmp (pn, "dmult", 5) == 0
+             || strstr (pn, "div"))
+           min_nops = 1;
          if (nops < min_nops)
            nops = min_nops;
        }
@@ -2779,14 +2906,78 @@ mips_emit_delays (bfd_boolean insns)
   mips_no_prev_insn (insns);
 }
 
+/* Set up global variables for the start of a new macro.  */
+
+static void
+macro_start (void)
+{
+  memset (&mips_macro_warning.sizes, 0, sizeof (mips_macro_warning.sizes));
+  mips_macro_warning.delay_slot_p = (mips_opts.noreorder
+                                    && (prev_insn.insn_mo->pinfo
+                                        & (INSN_UNCOND_BRANCH_DELAY
+                                           | INSN_COND_BRANCH_DELAY
+                                           | INSN_COND_BRANCH_LIKELY)) != 0);
+}
+
+/* Given that a macro is longer than 4 bytes, return the appropriate warning
+   for it.  Return null if no warning is needed.  SUBTYPE is a bitmask of
+   RELAX_DELAY_SLOT and RELAX_NOMACRO.  */
+
+static const char *
+macro_warning (relax_substateT subtype)
+{
+  if (subtype & RELAX_DELAY_SLOT)
+    return _("Macro instruction expanded into multiple instructions"
+            " in a branch delay slot");
+  else if (subtype & RELAX_NOMACRO)
+    return _("Macro instruction expanded into multiple instructions");
+  else
+    return 0;
+}
+
+/* Finish up a macro.  Emit warnings as appropriate.  */
+
+static void
+macro_end (void)
+{
+  if (mips_macro_warning.sizes[0] > 4 || mips_macro_warning.sizes[1] > 4)
+    {
+      relax_substateT subtype;
+
+      /* Set up the relaxation warning flags.  */
+      subtype = 0;
+      if (mips_macro_warning.sizes[1] > mips_macro_warning.sizes[0])
+       subtype |= RELAX_SECOND_LONGER;
+      if (mips_opts.warn_about_macros)
+       subtype |= RELAX_NOMACRO;
+      if (mips_macro_warning.delay_slot_p)
+       subtype |= RELAX_DELAY_SLOT;
+
+      if (mips_macro_warning.sizes[0] > 4 && mips_macro_warning.sizes[1] > 4)
+       {
+         /* Either the macro has a single implementation or both
+            implementations are longer than 4 bytes.  Emit the
+            warning now.  */
+         const char *msg = macro_warning (subtype);
+         if (msg != 0)
+           as_warn (msg);
+       }
+      else
+       {
+         /* One implementation might need a warning but the other
+            definitely doesn't.  */
+         mips_macro_warning.first_frag->fr_subtype |= subtype;
+       }
+    }
+}
+
 /* Build an instruction created by a macro expansion.  This is passed
    a pointer to the count of instructions created so far, an
    expression, the name of the instruction to build, an operand format
    string, and corresponding arguments.  */
 
 static void
-macro_build (char *place, int *counter, expressionS *ep, const char *name,
-            const char *fmt, ...)
+macro_build (expressionS *ep, const char *name, const char *fmt, ...)
 {
   struct mips_cl_insn insn;
   bfd_reloc_code_real_type r[3];
@@ -2794,32 +2985,9 @@ macro_build (char *place, int *counter, expressionS *ep, const char *name,
 
   va_start (args, fmt);
 
-  /*
-   * If the macro is about to expand into a second instruction,
-   * print a warning if needed. We need to pass ip as a parameter
-   * to generate a better warning message here...
-   */
-  if (mips_opts.warn_about_macros && place == NULL && *counter == 1)
-    as_warn (_("Macro instruction expanded into multiple instructions"));
-
-  /*
-   * If the macro is about to expand into a second instruction,
-   * and it is in a delay slot, print a warning.
-   */
-  if (place == NULL
-      && *counter == 1
-      && mips_opts.noreorder
-      && (prev_prev_insn.insn_mo->pinfo
-         & (INSN_UNCOND_BRANCH_DELAY | INSN_COND_BRANCH_DELAY
-            | INSN_COND_BRANCH_LIKELY)) != 0)
-    as_warn (_("Macro instruction expanded into multiple instructions in a branch delay slot"));
-
-  if (place == NULL)
-    ++*counter;                /* bump instruction counter */
-
   if (mips_opts.mips16)
     {
-      mips16_macro_build (place, counter, ep, name, fmt, args);
+      mips16_macro_build (ep, name, fmt, args);
       va_end (args);
       return;
     }
@@ -2978,9 +3146,7 @@ macro_build (char *place, int *counter, expressionS *ep, const char *name,
                  || *r == BFD_RELOC_MIPS_GOT_PAGE
                  || *r == BFD_RELOC_MIPS_GOT_OFST
                  || *r == BFD_RELOC_MIPS_GOT_LO16
-                 || *r == BFD_RELOC_MIPS_CALL_LO16
-                 || (ep->X_op == O_subtract
-                     && *r == BFD_RELOC_PCREL_LO16));
+                 || *r == BFD_RELOC_MIPS_CALL_LO16);
          continue;
 
        case 'u':
@@ -2993,9 +3159,7 @@ macro_build (char *place, int *counter, expressionS *ep, const char *name,
                              || *r == BFD_RELOC_HI16
                              || *r == BFD_RELOC_GPREL16
                              || *r == BFD_RELOC_MIPS_GOT_HI16
-                             || *r == BFD_RELOC_MIPS_CALL_HI16))
-                     || (ep->X_op == O_subtract
-                         && *r == BFD_RELOC_PCREL_HI16_S)));
+                             || *r == BFD_RELOC_MIPS_CALL_HI16))));
          continue;
 
        case 'p':
@@ -3033,12 +3197,11 @@ macro_build (char *place, int *counter, expressionS *ep, const char *name,
   va_end (args);
   assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
 
-  append_insn (place, &insn, ep, r);
+  append_insn (&insn, ep, r);
 }
 
 static void
-mips16_macro_build (char *place, int *counter ATTRIBUTE_UNUSED,
-                   expressionS *ep, const char *name, const char *fmt,
+mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
                    va_list args)
 {
   struct mips_cl_insn insn;
@@ -3155,7 +3318,7 @@ mips16_macro_build (char *place, int *counter ATTRIBUTE_UNUSED,
 
   assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
 
-  append_insn (place, &insn, ep, r);
+  append_insn (&insn, ep, r);
 }
 
 /*
@@ -3163,16 +3326,16 @@ mips16_macro_build (char *place, int *counter ATTRIBUTE_UNUSED,
  * function.  This occurs in NewABI PIC code.
  */
 static void
-macro_build_jalr (int icnt, expressionS *ep)
+macro_build_jalr (expressionS *ep)
 {
   char *f = NULL;
 
   if (HAVE_NEWABI)
     {
-      frag_grow (4);
+      frag_grow (8);
       f = frag_more (0);
     }
-  macro_build (NULL, &icnt, NULL, "jalr", "d,s", RA, PIC_CALL_REG);
+  macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
   if (HAVE_NEWABI)
     fix_new_exp (frag_now, f - frag_now->fr_literal,
                 4, ep, FALSE, BFD_RELOC_MIPS_JALR);
@@ -3182,7 +3345,7 @@ macro_build_jalr (int icnt, expressionS *ep)
  * Generate a "lui" instruction.
  */
 static void
-macro_build_lui (char *place, int *counter, expressionS *ep, int regnum)
+macro_build_lui (expressionS *ep, int regnum)
 {
   expressionS high_expr;
   struct mips_cl_insn insn;
@@ -3193,13 +3356,7 @@ macro_build_lui (char *place, int *counter, expressionS *ep, int regnum)
 
   assert (! mips_opts.mips16);
 
-  if (place == NULL)
-    high_expr = *ep;
-  else
-    {
-      high_expr.X_op = O_constant;
-      high_expr.X_add_number = ep->X_add_number;
-    }
+  high_expr = *ep;
 
   if (high_expr.X_op == O_constant)
     {
@@ -3218,17 +3375,6 @@ macro_build_lui (char *place, int *counter, expressionS *ep, int regnum)
       *r = BFD_RELOC_HI16_S;
     }
 
-  /*
-   * If the macro is about to expand into a second instruction,
-   * print a warning if needed. We need to pass ip as a parameter
-   * to generate a better warning message here...
-   */
-  if (mips_opts.warn_about_macros && place == NULL && *counter == 1)
-    as_warn (_("Macro instruction expanded into multiple instructions"));
-
-  if (place == NULL)
-    ++*counter;                /* bump instruction counter */
-
   insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name);
   assert (insn.insn_mo);
   assert (strcmp (name, insn.insn_mo->name) == 0);
@@ -3238,18 +3384,18 @@ macro_build_lui (char *place, int *counter, expressionS *ep, int regnum)
   if (*r == BFD_RELOC_UNUSED)
     {
       insn.insn_opcode |= high_expr.X_add_number;
-      append_insn (place, &insn, NULL, r);
+      append_insn (&insn, NULL, r);
     }
   else
-    append_insn (place, &insn, &high_expr, r);
+    append_insn (&insn, &high_expr, r);
 }
 
 /* Generate a sequence of instructions to do a load or store from a constant
    offset off of a base register (breg) into/from a target register (treg),
    using AT if necessary.  */
 static void
-macro_build_ldst_constoffset (char *place, int *counter, expressionS *ep,
-                             const char *op, int treg, int breg, int dbl)
+macro_build_ldst_constoffset (expressionS *ep, const char *op,
+                             int treg, int breg, int dbl)
 {
   assert (ep->X_op == O_constant);
 
@@ -3271,8 +3417,7 @@ macro_build_ldst_constoffset (char *place, int *counter, expressionS *ep,
   if (IS_SEXT_16BIT_NUM(ep->X_add_number))
     {
       /* Signed 16-bit offset will fit in the op.  Easy!  */
-      macro_build (place, counter, ep, op, "t,o(b)", treg, BFD_RELOC_LO16,
-                  breg);
+      macro_build (ep, op, "t,o(b)", treg, BFD_RELOC_LO16, breg);
     }
   else
     {
@@ -3281,15 +3426,9 @@ macro_build_ldst_constoffset (char *place, int *counter, expressionS *ep,
           addu     $tempreg,$tempreg,$breg
            <op>     $treg,const_lo($tempreg)   (BFD_RELOC_LO16)
          to handle the complete offset.  */
-      macro_build_lui (place, counter, ep, AT);
-      if (place != NULL)
-       place += 4;
-      macro_build (place, counter, NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT,
-                  breg);
-      if (place != NULL)
-       place += 4;
-      macro_build (place, counter, ep, op, "t,o(b)", treg, BFD_RELOC_LO16,
-                  AT);
+      macro_build_lui (ep, AT);
+      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
+      macro_build (ep, op, "t,o(b)", treg, BFD_RELOC_LO16, AT);
 
       if (mips_opts.noat)
        as_warn (_("Macro used $at after \".set noat\""));
@@ -3301,18 +3440,17 @@ macro_build_ldst_constoffset (char *place, int *counter, expressionS *ep,
  * if reg is less than the immediate expression.
  */
 static void
-set_at (int *counter, int reg, int unsignedp)
+set_at (int reg, int unsignedp)
 {
   if (imm_expr.X_op == O_constant
       && imm_expr.X_add_number >= -0x8000
       && imm_expr.X_add_number < 0x8000)
-    macro_build (NULL, counter, &imm_expr, unsignedp ? "sltiu" : "slti",
-                "t,r,j", AT, reg, BFD_RELOC_LO16);
+    macro_build (&imm_expr, unsignedp ? "sltiu" : "slti", "t,r,j",
+                AT, reg, BFD_RELOC_LO16);
   else
     {
-      load_register (counter, AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, counter, NULL, unsignedp ? "sltu" : "slt",
-                  "d,v,t", AT, reg, AT);
+      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      macro_build (NULL, unsignedp ? "sltu" : "slt", "d,v,t", AT, reg, AT);
     }
 }
 
@@ -3418,7 +3556,7 @@ check_absolute_expr (struct mips_cl_insn *ip, expressionS *ex)
  *  an absolute expression value into a register.
  */
 static void
-load_register (int *counter, int reg, expressionS *ep, int dbl)
+load_register (int reg, expressionS *ep, int dbl)
 {
   int freg;
   expressionS hi32, lo32;
@@ -3443,25 +3581,22 @@ load_register (int *counter, int reg, expressionS *ep, int dbl)
          /* We can handle 16 bit signed values with an addiu to
             $zero.  No need to ever use daddiu here, since $zero and
             the result are always correct in 32 bit mode.  */
-         macro_build (NULL, counter, ep, "addiu", "t,r,j", reg, 0,
-                      BFD_RELOC_LO16);
+         macro_build (ep, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
          return;
        }
       else if (ep->X_add_number >= 0 && ep->X_add_number < 0x10000)
        {
          /* We can handle 16 bit unsigned values with an ori to
              $zero.  */
-         macro_build (NULL, counter, ep, "ori", "t,r,i", reg, 0,
-                      BFD_RELOC_LO16);
+         macro_build (ep, "ori", "t,r,i", reg, 0, BFD_RELOC_LO16);
          return;
        }
       else if ((IS_SEXT_32BIT_NUM (ep->X_add_number)))
        {
          /* 32 bit values require an lui.  */
-         macro_build (NULL, counter, ep, "lui", "t,u", reg, BFD_RELOC_HI16);
+         macro_build (ep, "lui", "t,u", reg, BFD_RELOC_HI16);
          if ((ep->X_add_number & 0xffff) != 0)
-           macro_build (NULL, counter, ep, "ori", "t,r,i", reg, reg,
-                        BFD_RELOC_LO16);
+           macro_build (ep, "ori", "t,r,i", reg, reg, BFD_RELOC_LO16);
          return;
        }
     }
@@ -3472,8 +3607,7 @@ load_register (int *counter, int reg, expressionS *ep, int dbl)
     {
       as_bad (_("Number (0x%lx) larger than 32 bits"),
              (unsigned long) ep->X_add_number);
-      macro_build (NULL, counter, ep, "addiu", "t,r,j", reg, 0,
-                  BFD_RELOC_LO16);
+      macro_build (ep, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
       return;
     }
 
@@ -3510,17 +3644,14 @@ load_register (int *counter, int reg, expressionS *ep, int dbl)
        {
          if ((lo32.X_add_number & 0xffff8000) == 0xffff8000)
            {
-             macro_build (NULL, counter, &lo32, "addiu", "t,r,j", reg, 0,
-                          BFD_RELOC_LO16);
+             macro_build (&lo32, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
              return;
            }
          if (lo32.X_add_number & 0x80000000)
            {
-             macro_build (NULL, counter, &lo32, "lui", "t,u", reg,
-                          BFD_RELOC_HI16);
+             macro_build (&lo32, "lui", "t,u", reg, BFD_RELOC_HI16);
              if (lo32.X_add_number & 0xffff)
-               macro_build (NULL, counter, &lo32, "ori", "t,r,i", reg, reg,
-                            BFD_RELOC_LO16);
+               macro_build (&lo32, "ori", "t,r,i", reg, reg, BFD_RELOC_LO16);
              return;
            }
        }
@@ -3554,12 +3685,9 @@ load_register (int *counter, int reg, expressionS *ep, int dbl)
                                    | (lo32.X_add_number >> shift));
              else
                tmp.X_add_number = hi32.X_add_number >> (shift - 32);
-             macro_build (NULL, counter, &tmp, "ori", "t,r,i", reg, 0,
-                          BFD_RELOC_LO16);
-             macro_build (NULL, counter, NULL,
-                          (shift >= 32) ? "dsll32" : "dsll",
-                          "d,w,<", reg, reg,
-                          (shift >= 32) ? shift - 32 : shift);
+             macro_build (&tmp, "ori", "t,r,i", reg, 0, BFD_RELOC_LO16);
+             macro_build (NULL, (shift >= 32) ? "dsll32" : "dsll", "d,w,<",
+                          reg, reg, (shift >= 32) ? shift - 32 : shift);
              return;
            }
          ++shift;
@@ -3606,20 +3734,15 @@ load_register (int *counter, int reg, expressionS *ep, int dbl)
                  ones.  */
              tmp.X_op = O_constant;
              tmp.X_add_number = (offsetT) -1;
-             macro_build (NULL, counter, &tmp, "addiu", "t,r,j", reg, 0,
-                          BFD_RELOC_LO16);
+             macro_build (&tmp, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
              if (bit != 0)
                {
                  bit += shift;
-                 macro_build (NULL, counter, NULL,
-                              (bit >= 32) ? "dsll32" : "dsll",
-                              "d,w,<", reg, reg,
-                              (bit >= 32) ? bit - 32 : bit);
+                 macro_build (NULL, (bit >= 32) ? "dsll32" : "dsll", "d,w,<",
+                              reg, reg, (bit >= 32) ? bit - 32 : bit);
                }
-             macro_build (NULL, counter, NULL,
-                          (shift >= 32) ? "dsrl32" : "dsrl",
-                          "d,w,<", reg, reg,
-                          (shift >= 32) ? shift - 32 : shift);
+             macro_build (NULL, (shift >= 32) ? "dsrl32" : "dsrl", "d,w,<",
+                          reg, reg, (shift >= 32) ? shift - 32 : shift);
              return;
            }
        }
@@ -3628,14 +3751,14 @@ load_register (int *counter, int reg, expressionS *ep, int dbl)
          generally get better code when we load a sign extended value.  */
       if ((hi32.X_add_number & 0x80000000) != 0)
        hi32.X_add_number |= ~(offsetT) 0xffffffff;
-      load_register (counter, reg, &hi32, 0);
+      load_register (reg, &hi32, 0);
       freg = reg;
     }
   if ((lo32.X_add_number & 0xffff0000) == 0)
     {
       if (freg != 0)
        {
-         macro_build (NULL, counter, NULL, "dsll32", "d,w,<", reg, freg, 0);
+         macro_build (NULL, "dsll32", "d,w,<", reg, freg, 0);
          freg = reg;
        }
     }
@@ -3645,36 +3768,38 @@ load_register (int *counter, int reg, expressionS *ep, int dbl)
 
       if ((freg == 0) && (lo32.X_add_number == (offsetT) 0xffffffff))
        {
-         macro_build (NULL, counter, &lo32, "lui", "t,u", reg,
-                      BFD_RELOC_HI16);
-         macro_build (NULL, counter, NULL, "dsrl32", "d,w,<", reg, reg, 0);
+         macro_build (&lo32, "lui", "t,u", reg, BFD_RELOC_HI16);
+         macro_build (NULL, "dsrl32", "d,w,<", reg, reg, 0);
          return;
        }
 
       if (freg != 0)
        {
-         macro_build (NULL, counter, NULL, "dsll", "d,w,<", reg, freg, 16);
+         macro_build (NULL, "dsll", "d,w,<", reg, freg, 16);
          freg = reg;
        }
       mid16 = lo32;
       mid16.X_add_number >>= 16;
-      macro_build (NULL, counter, &mid16, "ori", "t,r,i", reg, freg,
-                  BFD_RELOC_LO16);
-      macro_build (NULL, counter, NULL, "dsll", "d,w,<", reg, reg, 16);
+      macro_build (&mid16, "ori", "t,r,i", reg, freg, BFD_RELOC_LO16);
+      macro_build (NULL, "dsll", "d,w,<", reg, reg, 16);
       freg = reg;
     }
   if ((lo32.X_add_number & 0xffff) != 0)
-    macro_build (NULL, counter, &lo32, "ori", "t,r,i", reg, freg,
-                BFD_RELOC_LO16);
+    macro_build (&lo32, "ori", "t,r,i", reg, freg, BFD_RELOC_LO16);
+}
+
+static inline void
+load_delay_nop (void)
+{
+  if (!gpr_interlocks)
+    macro_build (NULL, "nop", "");
 }
 
 /* Load an address into a register.  */
 
 static void
-load_address (int *counter, int reg, expressionS *ep, int *used_at)
+load_address (int reg, expressionS *ep, int *used_at)
 {
-  char *p = NULL;
-
   if (ep->X_op != O_constant
       && ep->X_op != O_symbol)
     {
@@ -3684,7 +3809,7 @@ load_address (int *counter, int reg, expressionS *ep, int *used_at)
 
   if (ep->X_op == O_constant)
     {
-      load_register (counter, reg, ep, HAVE_64BIT_ADDRESSES);
+      load_register (reg, ep, HAVE_64BIT_ADDRESSES);
       return;
     }
 
@@ -3716,35 +3841,30 @@ load_address (int *counter, int reg, expressionS *ep, int *used_at)
        */
       if (HAVE_64BIT_ADDRESSES)
        {
-         /* We don't do GP optimization for now because RELAX_ENCODE can't
-            hold the data for such large chunks.  */
+         /* ??? We don't provide a GP-relative alternative for these macros.
+            It used not to be possible with the original relaxation code,
+            but it could be done now.  */
 
          if (*used_at == 0 && ! mips_opts.noat)
            {
-             macro_build (p, counter, ep, "lui", "t,u",
-                          reg, BFD_RELOC_MIPS_HIGHEST);
-             macro_build (p, counter, ep, "lui", "t,u",
-                          AT, BFD_RELOC_HI16_S);
-             macro_build (p, counter, ep, "daddiu", "t,r,j",
-                          reg, reg, BFD_RELOC_MIPS_HIGHER);
-             macro_build (p, counter, ep, "daddiu", "t,r,j",
-                          AT, AT, BFD_RELOC_LO16);
-             macro_build (p, counter, NULL, "dsll32", "d,w,<", reg, reg, 0);
-             macro_build (p, counter, NULL, "daddu", "d,v,t", reg, reg, AT);
+             macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_HIGHEST);
+             macro_build (ep, "lui", "t,u", AT, BFD_RELOC_HI16_S);
+             macro_build (ep, "daddiu", "t,r,j", reg, reg,
+                          BFD_RELOC_MIPS_HIGHER);
+             macro_build (ep, "daddiu", "t,r,j", AT, AT, BFD_RELOC_LO16);
+             macro_build (NULL, "dsll32", "d,w,<", reg, reg, 0);
+             macro_build (NULL, "daddu", "d,v,t", reg, reg, AT);
              *used_at = 1;
            }
          else
            {
-             macro_build (p, counter, ep, "lui", "t,u",
-                          reg, BFD_RELOC_MIPS_HIGHEST);
-             macro_build (p, counter, ep, "daddiu", "t,r,j",
-                          reg, reg, BFD_RELOC_MIPS_HIGHER);
-             macro_build (p, counter, NULL, "dsll", "d,w,<", reg, reg, 16);
-             macro_build (p, counter, ep, "daddiu", "t,r,j",
-                          reg, reg, BFD_RELOC_HI16_S);
-             macro_build (p, counter, NULL, "dsll", "d,w,<", reg, reg, 16);
-             macro_build (p, counter, ep, "daddiu", "t,r,j",
-                          reg, reg, BFD_RELOC_LO16);
+             macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_HIGHEST);
+             macro_build (ep, "daddiu", "t,r,j", reg, reg,
+                          BFD_RELOC_MIPS_HIGHER);
+             macro_build (NULL, "dsll", "d,w,<", reg, reg, 16);
+             macro_build (ep, "daddiu", "t,r,j", reg, reg, BFD_RELOC_HI16_S);
+             macro_build (NULL, "dsll", "d,w,<", reg, reg, 16);
+             macro_build (ep, "daddiu", "t,r,j", reg, reg, BFD_RELOC_LO16);
            }
        }
       else
@@ -3752,19 +3872,16 @@ load_address (int *counter, int reg, expressionS *ep, int *used_at)
          if ((valueT) ep->X_add_number <= MAX_GPREL_OFFSET
              && ! nopic_need_relax (ep->X_add_symbol, 1))
            {
-             frag_grow (20);
-             macro_build (NULL, counter, ep, ADDRESS_ADDI_INSN, "t,r,j", reg,
+             relax_start (ep->X_add_symbol);
+             macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg,
                           mips_gp_register, BFD_RELOC_GPREL16);
-             p = frag_var (rs_machine_dependent, 8, 0,
-                           RELAX_ENCODE (4, 8, 0, 4, 0,
-                                         mips_opts.warn_about_macros),
-                           ep->X_add_symbol, 0, NULL);
+             relax_switch ();
            }
-         macro_build_lui (p, counter, ep, reg);
-         if (p != NULL)
-           p += 4;
-         macro_build (p, counter, ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
-                      BFD_RELOC_LO16);
+         macro_build_lui (ep, reg);
+         macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j",
+                      reg, reg, BFD_RELOC_LO16);
+         if (mips_relax.sequence)
+           relax_end ();
        }
     }
   else if (mips_pic == SVR4_PIC && ! mips_big_got)
@@ -3785,59 +3902,45 @@ load_address (int *counter, int reg, expressionS *ep, int *used_at)
          offset, in which case cst must be added separately.  */
       if (HAVE_NEWABI)
        {
-         frag_grow (12);
-
          if (ep->X_add_number)
            {
-             frag_now->tc_frag_data.tc_fr_offset =
-               ex.X_add_number = ep->X_add_number;
+             ex.X_add_number = ep->X_add_number;
              ep->X_add_number = 0;
-             macro_build (NULL, counter, ep, ADDRESS_LOAD_INSN, "t,o(b)",
-                          reg, BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
+             relax_start (ep->X_add_symbol);
+             macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
+                          BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
              if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
                as_bad (_("PIC code offset overflow (max 16 signed bits)"));
              ex.X_op = O_constant;
-             macro_build (NULL, counter, &ex, ADDRESS_ADDI_INSN, "t,r,j",
+             macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j",
                           reg, reg, BFD_RELOC_LO16);
-             p = frag_var (rs_machine_dependent, 8, 0,
-                           RELAX_ENCODE (8, 4, 0, 0, 0,
-                                         mips_opts.warn_about_macros),
-                           ep->X_add_symbol, 0, NULL);
              ep->X_add_number = ex.X_add_number;
+             relax_switch ();
            }
-
-         macro_build (p, counter, ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
+         macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
                       BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
-
-         if (! p)
-           {
-             /* To avoid confusion in tc_gen_reloc, we must ensure
-                that this does not become a variant frag.  */
-             frag_wane (frag_now);
-             frag_new (0);
-           }
+         if (mips_relax.sequence)
+           relax_end ();
        }
       else
        {
          ex.X_add_number = ep->X_add_number;
          ep->X_add_number = 0;
-         frag_grow (20);
-         macro_build (NULL, counter, ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
-                      BFD_RELOC_MIPS_GOT16,
-                      mips_gp_register);
-         macro_build (NULL, counter, NULL, "nop", "");
-         p = frag_var (rs_machine_dependent, 4, 0,
-                       RELAX_ENCODE (0, 4, -8, 0, 0, mips_opts.warn_about_macros),
-                       ep->X_add_symbol, 0, NULL);
-         macro_build (p, counter, ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
+         macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
+                      BFD_RELOC_MIPS_GOT16, mips_gp_register);
+         load_delay_nop ();
+         relax_start (ep->X_add_symbol);
+         relax_switch ();
+         macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
                       BFD_RELOC_LO16);
+         relax_end ();
 
          if (ex.X_add_number != 0)
            {
              if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
                as_bad (_("PIC code offset overflow (max 16 signed bits)"));
              ex.X_op = O_constant;
-             macro_build (NULL, counter, &ex, ADDRESS_ADDI_INSN, "t,r,j",
+             macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j",
                           reg, reg, BFD_RELOC_LO16);
            }
        }
@@ -3845,7 +3948,6 @@ load_address (int *counter, int reg, expressionS *ep, int *used_at)
   else if (mips_pic == SVR4_PIC)
     {
       expressionS ex;
-      int off;
 
       /* This is the large GOT case.  If this is a reference to an
         external symbol, we want
@@ -3865,90 +3967,67 @@ load_address (int *counter, int reg, expressionS *ep, int *used_at)
       */
       if (HAVE_NEWABI)
        {
-         frag_grow (24);
-
-         frag_now->tc_frag_data.tc_fr_offset =
-           ex.X_add_number = ep->X_add_number;
+         ex.X_add_number = ep->X_add_number;
          ep->X_add_number = 0;
-         macro_build (NULL, counter, ep, "lui", "t,u", reg,
-                      BFD_RELOC_MIPS_GOT_HI16);
-         macro_build (NULL, counter, NULL, ADDRESS_ADD_INSN, "d,v,t", reg,
-                      reg, mips_gp_register);
-         macro_build (NULL, counter, ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
-                      BFD_RELOC_MIPS_GOT_LO16, reg);
+         relax_start (ep->X_add_symbol);
+         macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_GOT_HI16);
+         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+                      reg, reg, mips_gp_register);
+         macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)",
+                      reg, BFD_RELOC_MIPS_GOT_LO16, reg);
          if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          else if (ex.X_add_number)
            {
              ex.X_op = O_constant;
-             macro_build (NULL, counter, &ex, ADDRESS_ADDI_INSN, "t,r,j",
-                          reg, reg, BFD_RELOC_LO16);
+             macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
+                          BFD_RELOC_LO16);
            }
 
          ep->X_add_number = ex.X_add_number;
-         p = frag_var (rs_machine_dependent, 8, 0,
-                       RELAX_ENCODE (ex.X_add_number ? 16 : 12, 8, 0, 4, 0,
-                                     mips_opts.warn_about_macros),
-                       ep->X_add_symbol, 0, NULL);
-         macro_build (p, counter, ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
+         relax_switch ();
+         macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
                       BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
-         macro_build (p + 4, counter, ep, ADDRESS_ADDI_INSN, "t,r,j", reg,
-                      reg, BFD_RELOC_MIPS_GOT_OFST);
+         macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
+                      BFD_RELOC_MIPS_GOT_OFST);
+         relax_end ();
        }
       else
        {
          ex.X_add_number = ep->X_add_number;
          ep->X_add_number = 0;
+         relax_start (ep->X_add_symbol);
+         macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_GOT_HI16);
+         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+                      reg, reg, mips_gp_register);
+         macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)",
+                      reg, BFD_RELOC_MIPS_GOT_LO16, reg);
+         relax_switch ();
          if (reg_needs_delay (mips_gp_register))
-           off = 4;
-         else
-           off = 0;
-         frag_grow (32);
-         macro_build (NULL, counter, ep, "lui", "t,u", reg,
-                      BFD_RELOC_MIPS_GOT_HI16);
-         macro_build (NULL, counter, NULL, ADDRESS_ADD_INSN, "d,v,t", reg,
-                      reg, mips_gp_register);
-         macro_build (NULL, counter, ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
-                      BFD_RELOC_MIPS_GOT_LO16, reg);
-         p = frag_var (rs_machine_dependent, 12 + off, 0,
-                       RELAX_ENCODE (12, 12 + off, off, 8 + off, 0,
-                                     mips_opts.warn_about_macros),
-                       ep->X_add_symbol, 0, NULL);
-         if (off > 0)
            {
              /* We need a nop before loading from $gp.  This special
                 check is required because the lui which starts the main
                 instruction stream does not refer to $gp, and so will not
                 insert the nop which may be required.  */
-             macro_build (p, counter, NULL, "nop", "");
-               p += 4;
+             macro_build (NULL, "nop", "");
            }
-         macro_build (p, counter, ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
+         macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
                       BFD_RELOC_MIPS_GOT16, mips_gp_register);
-         p += 4;
-         macro_build (p, counter, NULL, "nop", "");
-         p += 4;
-         macro_build (p, counter, ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
+         load_delay_nop ();
+         macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
                       BFD_RELOC_LO16);
+         relax_end ();
 
          if (ex.X_add_number != 0)
            {
              if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
                as_bad (_("PIC code offset overflow (max 16 signed bits)"));
              ex.X_op = O_constant;
-             macro_build (NULL, counter, &ex, ADDRESS_ADDI_INSN, "t,r,j",
-                          reg, reg, BFD_RELOC_LO16);
+             macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
+                          BFD_RELOC_LO16);
            }
        }
     }
-  else if (mips_pic == EMBEDDED_PIC)
-    {
-      /* We always do
-          addiu        $reg,$gp,<sym>          (BFD_RELOC_GPREL16)
-       */
-      macro_build (NULL, counter, ep, ADDRESS_ADDI_INSN, "t,r,j", reg,
-                  mips_gp_register, BFD_RELOC_GPREL16);
-    }
   else
     abort ();
 }
@@ -3956,10 +4035,85 @@ load_address (int *counter, int reg, expressionS *ep, int *used_at)
 /* Move the contents of register SOURCE into register DEST.  */
 
 static void
-move_register (int *counter, int dest, int source)
+move_register (int dest, int source)
+{
+  macro_build (NULL, HAVE_32BIT_GPRS ? "addu" : "daddu", "d,v,t",
+              dest, source, 0);
+}
+
+/* Emit an SVR4 PIC sequence to load address LOCAL into DEST, where
+   LOCAL is the sum of a symbol and a 16-bit or 32-bit displacement.
+   The two alternatives are:
+
+   Global symbol               Local sybmol
+   -------------               ------------
+   lw DEST,%got(SYMBOL)                lw DEST,%got(SYMBOL + OFFSET)
+   ...                         ...
+   addiu DEST,DEST,OFFSET      addiu DEST,DEST,%lo(SYMBOL + OFFSET)
+
+   load_got_offset emits the first instruction and add_got_offset
+   emits the second for a 16-bit offset or add_got_offset_hilo emits
+   a sequence to add a 32-bit offset using a scratch register.  */
+
+static void
+load_got_offset (int dest, expressionS *local)
+{
+  expressionS global;
+
+  global = *local;
+  global.X_add_number = 0;
+
+  relax_start (local->X_add_symbol);
+  macro_build (&global, ADDRESS_LOAD_INSN, "t,o(b)", dest,
+              BFD_RELOC_MIPS_GOT16, mips_gp_register);
+  relax_switch ();
+  macro_build (local, ADDRESS_LOAD_INSN, "t,o(b)", dest,
+              BFD_RELOC_MIPS_GOT16, mips_gp_register);
+  relax_end ();
+}
+
+static void
+add_got_offset (int dest, expressionS *local)
 {
-  macro_build (NULL, counter, NULL, HAVE_32BIT_GPRS ? "addu" : "daddu",
-              "d,v,t", dest, source, 0);
+  expressionS global;
+
+  global.X_op = O_constant;
+  global.X_op_symbol = NULL;
+  global.X_add_symbol = NULL;
+  global.X_add_number = local->X_add_number;
+
+  relax_start (local->X_add_symbol);
+  macro_build (&global, ADDRESS_ADDI_INSN, "t,r,j",
+              dest, dest, BFD_RELOC_LO16);
+  relax_switch ();
+  macro_build (local, ADDRESS_ADDI_INSN, "t,r,j", dest, dest, BFD_RELOC_LO16);
+  relax_end ();
+}
+
+static void
+add_got_offset_hilo (int dest, expressionS *local, int tmp)
+{
+  expressionS global;
+  int hold_mips_optimize;
+
+  global.X_op = O_constant;
+  global.X_op_symbol = NULL;
+  global.X_add_symbol = NULL;
+  global.X_add_number = local->X_add_number;
+
+  relax_start (local->X_add_symbol);
+  load_register (tmp, &global, HAVE_64BIT_ADDRESSES);
+  relax_switch ();
+  /* Set mips_optimize around the lui instruction to avoid
+     inserting an unnecessary nop after the lw.  */
+  hold_mips_optimize = mips_optimize;
+  mips_optimize = 2;
+  macro_build_lui (&global, tmp);
+  mips_optimize = hold_mips_optimize;
+  macro_build (local, ADDRESS_ADDI_INSN, "t,r,j", tmp, tmp, BFD_RELOC_LO16);
+  relax_end ();
+
+  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dest, dest, tmp);
 }
 
 /*
@@ -3986,7 +4140,6 @@ macro (struct mips_cl_insn *ip)
   register int treg, sreg, dreg, breg;
   int tempreg;
   int mask;
-  int icnt = 0;
   int used_at = 0;
   expressionS expr1;
   const char *s;
@@ -3998,8 +4151,8 @@ macro (struct mips_cl_insn *ip)
   int lr = 0;
   int imm = 0;
   int call = 0;
-  offsetT maxnum;
   int off;
+  offsetT maxnum;
   bfd_reloc_code_real_type r;
   int hold_mips_optimize;
 
@@ -4015,30 +4168,6 @@ macro (struct mips_cl_insn *ip)
   expr1.X_add_symbol = NULL;
   expr1.X_add_number = 1;
 
-  /* Unmatched fixups should not be put in the same frag as a relaxable
-     macro.  For example, suppose we have:
-
-       lui $4,%hi(l1)          # 1
-       la $5,l2                # 2
-       addiu $4,$4,%lo(l1)     # 3
-
-     If instructions 1 and 2 were put in the same frag, md_frob_file would
-     move the fixup for #1 after the fixups for the "unrelaxed" version of
-     #2.  This would confuse tc_gen_reloc, which expects the relocations
-     for #2 to be the last for that frag.
-
-     Also, if tc_gen_reloc sees certain relocations in a variant frag,
-     it assumes that they belong to a relaxable macro.  We mustn't put
-     other uses of such relocations into a variant frag.
-
-     To avoid both problems, finish the current frag it contains a
-     %reloc() operator.  The macro then goes into a new frag.  */
-  if (prev_reloc_op_frag == frag_now)
-    {
-      frag_wane (frag_now);
-      frag_new (0);
-    }
-
   switch (mask)
     {
     case M_DABS:
@@ -4054,13 +4183,12 @@ macro (struct mips_cl_insn *ip)
       mips_any_noreorder = 1;
 
       expr1.X_add_number = 8;
-      macro_build (NULL, &icnt, &expr1, "bgez", "s,p", sreg);
+      macro_build (&expr1, "bgez", "s,p", sreg);
       if (dreg == sreg)
-       macro_build (NULL, &icnt, NULL, "nop", "", 0);
+       macro_build (NULL, "nop", "", 0);
       else
-       move_register (&icnt, dreg, sreg);
-      macro_build (NULL, &icnt, NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0,
-                  sreg);
+       move_register (dreg, sreg);
+      macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);
 
       --mips_opts.noreorder;
       return;
@@ -4087,12 +4215,11 @@ macro (struct mips_cl_insn *ip)
          && imm_expr.X_add_number >= -0x8000
          && imm_expr.X_add_number < 0x8000)
        {
-         macro_build (NULL, &icnt, &imm_expr, s, "t,r,j", treg, sreg,
-                      BFD_RELOC_LO16);
+         macro_build (&imm_expr, s, "t,r,j", treg, sreg, BFD_RELOC_LO16);
          return;
        }
-      load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build (NULL, &icnt, NULL, s2, "d,v,t", treg, sreg, AT);
+      load_register (AT, &imm_expr, dbl);
+      macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
       break;
 
     case M_AND_I:
@@ -4116,19 +4243,18 @@ macro (struct mips_cl_insn *ip)
          && imm_expr.X_add_number < 0x10000)
        {
          if (mask != M_NOR_I)
-           macro_build (NULL, &icnt, &imm_expr, s, "t,r,i", treg, sreg,
-                        BFD_RELOC_LO16);
+           macro_build (&imm_expr, s, "t,r,i", treg, sreg, BFD_RELOC_LO16);
          else
            {
-             macro_build (NULL, &icnt, &imm_expr, "ori", "t,r,i", treg, sreg,
-                          BFD_RELOC_LO16);
-             macro_build (NULL, &icnt, NULL, "nor", "d,v,t", treg, treg, 0);
+             macro_build (&imm_expr, "ori", "t,r,i",
+                          treg, sreg, BFD_RELOC_LO16);
+             macro_build (NULL, "nor", "d,v,t", treg, treg, 0);
            }
          return;
        }
 
-      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, &icnt, NULL, s2, "d,v,t", treg, sreg, AT);
+      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
       break;
 
     case M_BEQ_I:
@@ -4147,11 +4273,11 @@ macro (struct mips_cl_insn *ip)
     beq_i:
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, s, "s,t,p", sreg, 0);
+         macro_build (&offset_expr, s, "s,t,p", sreg, 0);
          return;
        }
-      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, &icnt, &offset_expr, s, "s,t,p", sreg, AT);
+      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      macro_build (&offset_expr, s, "s,t,p", sreg, AT);
       break;
 
     case M_BGEL:
@@ -4159,19 +4285,16 @@ macro (struct mips_cl_insn *ip)
     case M_BGE:
       if (treg == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "bgezl" : "bgez",
-                      "s,p", sreg);
+         macro_build (&offset_expr, likely ? "bgezl" : "bgez", "s,p", sreg);
          return;
        }
       if (sreg == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "blezl" : "blez",
-                      "s,p", treg);
+         macro_build (&offset_expr, likely ? "blezl" : "blez", "s,p", treg);
          return;
        }
-      macro_build (NULL, &icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
-      macro_build (NULL, &icnt, &offset_expr, likely ? "beql" : "beq",
-                  "s,t,p", AT, 0);
+      macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
+      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
 
     case M_BGTL_I:
@@ -4193,9 +4316,9 @@ macro (struct mips_cl_insn *ip)
        do_false:
          /* result is always false */
          if (! likely)
-           macro_build (NULL, &icnt, NULL, "nop", "", 0);
+           macro_build (NULL, "nop", "", 0);
          else
-           macro_build (NULL, &icnt, &offset_expr, "bnel", "s,t,p", 0, 0);
+           macro_build (&offset_expr, "bnel", "s,t,p", 0, 0);
          return;
        }
       if (imm_expr.X_op != O_constant)
@@ -4208,14 +4331,12 @@ macro (struct mips_cl_insn *ip)
        likely = 1;
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "bgezl" : "bgez",
-                      "s,p", sreg);
+         macro_build (&offset_expr, likely ? "bgezl" : "bgez", "s,p", sreg);
          return;
        }
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "bgtzl" : "bgtz",
-                      "s,p", sreg);
+         macro_build (&offset_expr, likely ? "bgtzl" : "bgtz", "s,p", sreg);
          return;
        }
       maxnum = 0x7fffffff;
@@ -4234,12 +4355,11 @@ macro (struct mips_cl_insn *ip)
        do_true:
          /* result is always true */
          as_warn (_("Branch %s is always true"), ip->insn_mo->name);
-         macro_build (NULL, &icnt, &offset_expr, "b", "p");
+         macro_build (&offset_expr, "b", "p");
          return;
        }
-      set_at (&icnt, sreg, 0);
-      macro_build (NULL, &icnt, &offset_expr, likely ? "beql" : "beq",
-                  "s,t,p", AT, 0);
+      set_at (sreg, 0);
+      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
 
     case M_BGEUL:
@@ -4249,13 +4369,12 @@ macro (struct mips_cl_insn *ip)
        goto do_true;
       if (sreg == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "beql" : "beq",
+         macro_build (&offset_expr, likely ? "beql" : "beq",
                       "s,t,p", 0, treg);
          return;
        }
-      macro_build (NULL, &icnt, NULL, "sltu", "d,v,t", AT, sreg, treg);
-      macro_build (NULL, &icnt, &offset_expr, likely ? "beql" : "beq",
-                  "s,t,p", AT, 0);
+      macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
+      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
 
     case M_BGTUL_I:
@@ -4278,13 +4397,12 @@ macro (struct mips_cl_insn *ip)
        goto do_true;
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "bnel" : "bne",
+         macro_build (&offset_expr, likely ? "bnel" : "bne",
                       "s,t,p", sreg, 0);
          return;
        }
-      set_at (&icnt, sreg, 1);
-      macro_build (NULL, &icnt, &offset_expr, likely ? "beql" : "beq",
-                  "s,t,p", AT, 0);
+      set_at (sreg, 1);
+      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
 
     case M_BGTL:
@@ -4292,19 +4410,16 @@ macro (struct mips_cl_insn *ip)
     case M_BGT:
       if (treg == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "bgtzl" : "bgtz",
-                      "s,p", sreg);
+         macro_build (&offset_expr, likely ? "bgtzl" : "bgtz", "s,p", sreg);
          return;
        }
       if (sreg == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "bltzl" : "bltz",
-                      "s,p", treg);
+         macro_build (&offset_expr, likely ? "bltzl" : "bltz", "s,p", treg);
          return;
        }
-      macro_build (NULL, &icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
-      macro_build (NULL, &icnt, &offset_expr, likely ? "bnel" : "bne",
-                  "s,t,p", AT, 0);
+      macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
+      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
 
     case M_BGTUL:
@@ -4312,15 +4427,14 @@ macro (struct mips_cl_insn *ip)
     case M_BGTU:
       if (treg == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "bnel" : "bne",
+         macro_build (&offset_expr, likely ? "bnel" : "bne",
                       "s,t,p", sreg, 0);
          return;
        }
       if (sreg == 0)
        goto do_false;
-      macro_build (NULL, &icnt, NULL, "sltu", "d,v,t", AT, treg, sreg);
-      macro_build (NULL, &icnt, &offset_expr, likely ? "bnel" : "bne",
-                  "s,t,p", AT, 0);
+      macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
+      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
 
     case M_BLEL:
@@ -4328,19 +4442,16 @@ macro (struct mips_cl_insn *ip)
     case M_BLE:
       if (treg == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "blezl" : "blez",
-                      "s,p", sreg);
+         macro_build (&offset_expr, likely ? "blezl" : "blez", "s,p", sreg);
          return;
        }
       if (sreg == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "bgezl" : "bgez",
-                      "s,p", treg);
+         macro_build (&offset_expr, likely ? "bgezl" : "bgez", "s,p", treg);
          return;
        }
-      macro_build (NULL, &icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
-      macro_build (NULL, &icnt, &offset_expr, likely ? "beql" : "beq",
-                  "s,t,p", AT, 0);
+      macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
+      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
 
     case M_BLEL_I:
@@ -4368,19 +4479,16 @@ macro (struct mips_cl_insn *ip)
        likely = 1;
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "bltzl" : "bltz",
-                      "s,p", sreg);
+         macro_build (&offset_expr, likely ? "bltzl" : "bltz", "s,p", sreg);
          return;
        }
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "blezl" : "blez",
-                      "s,p", sreg);
+         macro_build (&offset_expr, likely ? "blezl" : "blez", "s,p", sreg);
          return;
        }
-      set_at (&icnt, sreg, 0);
-      macro_build (NULL, &icnt, &offset_expr, likely ? "bnel" : "bne",
-                  "s,t,p", AT, 0);
+      set_at (sreg, 0);
+      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
 
     case M_BLEUL:
@@ -4388,15 +4496,14 @@ macro (struct mips_cl_insn *ip)
     case M_BLEU:
       if (treg == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "beql" : "beq",
+         macro_build (&offset_expr, likely ? "beql" : "beq",
                       "s,t,p", sreg, 0);
          return;
        }
       if (sreg == 0)
        goto do_true;
-      macro_build (NULL, &icnt, NULL, "sltu", "d,v,t", AT, treg, sreg);
-      macro_build (NULL, &icnt, &offset_expr, likely ? "beql" : "beq",
-                  "s,t,p", AT, 0);
+      macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
+      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
 
     case M_BLEUL_I:
@@ -4419,13 +4526,12 @@ macro (struct mips_cl_insn *ip)
        goto do_false;
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "beql" : "beq",
+         macro_build (&offset_expr, likely ? "beql" : "beq",
                       "s,t,p", sreg, 0);
          return;
        }
-      set_at (&icnt, sreg, 1);
-      macro_build (NULL, &icnt, &offset_expr, likely ? "bnel" : "bne",
-                  "s,t,p", AT, 0);
+      set_at (sreg, 1);
+      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
 
     case M_BLTL:
@@ -4433,19 +4539,16 @@ macro (struct mips_cl_insn *ip)
     case M_BLT:
       if (treg == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "bltzl" : "bltz",
-                      "s,p", sreg);
+         macro_build (&offset_expr, likely ? "bltzl" : "bltz", "s,p", sreg);
          return;
        }
       if (sreg == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "bgtzl" : "bgtz",
-                      "s,p", treg);
+         macro_build (&offset_expr, likely ? "bgtzl" : "bgtz", "s,p", treg);
          return;
        }
-      macro_build (NULL, &icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
-      macro_build (NULL, &icnt, &offset_expr, likely ? "bnel" : "bne",
-                  "s,t,p", AT, 0);
+      macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
+      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
 
     case M_BLTUL:
@@ -4455,13 +4558,12 @@ macro (struct mips_cl_insn *ip)
        goto do_false;
       if (sreg == 0)
        {
-         macro_build (NULL, &icnt, &offset_expr, likely ? "bnel" : "bne",
+         macro_build (&offset_expr, likely ? "bnel" : "bne",
                       "s,t,p", 0, treg);
          return;
        }
-      macro_build (NULL, &icnt, NULL, "sltu", "d,v,t", AT, sreg, treg);
-      macro_build (NULL, &icnt, &offset_expr, likely ? "bnel" : "bne",
-                  "s,t,p", AT, 0);
+      macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
+      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
 
     case M_DEXT:
@@ -4508,8 +4610,7 @@ macro (struct mips_cl_insn *ip)
            s = "dextm";
            fmt = "t,r,+A,+G";
          }
-       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s,
-                    fmt, treg, sreg, pos, size - 1);
+       macro_build ((expressionS *) NULL, s, fmt, treg, sreg, pos, size - 1);
       }
       return;
 
@@ -4557,8 +4658,8 @@ macro (struct mips_cl_insn *ip)
            s = "dinsm";
            fmt = "t,r,+A,+F";
          }
-       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s,
-                    fmt, treg, sreg, pos, pos + size - 1);
+       macro_build ((expressionS *) NULL, s, fmt, treg, sreg, pos,
+                    pos + size - 1);
       }
       return;
 
@@ -4576,9 +4677,9 @@ macro (struct mips_cl_insn *ip)
        {
          as_warn (_("Divide by zero."));
          if (mips_trap)
-           macro_build (NULL, &icnt, NULL, "teq", "s,t,q", 0, 0, 7);
+           macro_build (NULL, "teq", "s,t,q", 0, 0, 7);
          else
-           macro_build (NULL, &icnt, NULL, "break", "c", 7);
+           macro_build (NULL, "break", "c", 7);
          return;
        }
 
@@ -4587,39 +4688,34 @@ macro (struct mips_cl_insn *ip)
       mips_any_noreorder = 1;
       if (mips_trap)
        {
-         macro_build (NULL, &icnt, NULL, "teq", "s,t,q", treg, 0, 7);
-         macro_build (NULL, &icnt, NULL, dbl ? "ddiv" : "div", "z,s,t",
-                      sreg, treg);
+         macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
+         macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
        }
       else
        {
          expr1.X_add_number = 8;
-         macro_build (NULL, &icnt, &expr1, "bne", "s,t,p", treg, 0);
-         macro_build (NULL, &icnt, NULL, dbl ? "ddiv" : "div", "z,s,t",
-                      sreg, treg);
-         macro_build (NULL, &icnt, NULL, "break", "c", 7);
+         macro_build (&expr1, "bne", "s,t,p", treg, 0);
+         macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
+         macro_build (NULL, "break", "c", 7);
        }
       expr1.X_add_number = -1;
-      macro_build (NULL, &icnt, &expr1, dbl ? "daddiu" : "addiu", "t,r,j",
-                  AT, 0, BFD_RELOC_LO16);
+      load_register (AT, &expr1, dbl);
       expr1.X_add_number = mips_trap ? (dbl ? 12 : 8) : (dbl ? 20 : 16);
-      macro_build (NULL, &icnt, &expr1, "bne", "s,t,p", treg, AT);
+      macro_build (&expr1, "bne", "s,t,p", treg, AT);
       if (dbl)
        {
          expr1.X_add_number = 1;
-         macro_build (NULL, &icnt, &expr1, "daddiu", "t,r,j", AT, 0,
-                      BFD_RELOC_LO16);
-         macro_build (NULL, &icnt, NULL, "dsll32", "d,w,<", AT, AT, 31);
+         load_register (AT, &expr1, dbl);
+         macro_build (NULL, "dsll32", "d,w,<", AT, AT, 31);
        }
       else
        {
          expr1.X_add_number = 0x80000000;
-         macro_build (NULL, &icnt, &expr1, "lui", "t,u", AT,
-                      BFD_RELOC_HI16);
+         macro_build (&expr1, "lui", "t,u", AT, BFD_RELOC_HI16);
        }
       if (mips_trap)
        {
-         macro_build (NULL, &icnt, NULL, "teq", "s,t,q", sreg, AT, 6);
+         macro_build (NULL, "teq", "s,t,q", sreg, AT, 6);
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
          --mips_opts.noreorder;
@@ -4627,16 +4723,16 @@ macro (struct mips_cl_insn *ip)
       else
        {
          expr1.X_add_number = 8;
-         macro_build (NULL, &icnt, &expr1, "bne", "s,t,p", sreg, AT);
-         macro_build (NULL, &icnt, NULL, "nop", "", 0);
+         macro_build (&expr1, "bne", "s,t,p", sreg, AT);
+         macro_build (NULL, "nop", "", 0);
 
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
          --mips_opts.noreorder;
 
-         macro_build (NULL, &icnt, NULL, "break", "c", 6);
+         macro_build (NULL, "break", "c", 6);
        }
-      macro_build (NULL, &icnt, NULL, s, "d", dreg);
+      macro_build (NULL, s, "d", dreg);
       break;
 
     case M_DIV_3I:
@@ -4679,17 +4775,17 @@ macro (struct mips_cl_insn *ip)
        {
          as_warn (_("Divide by zero."));
          if (mips_trap)
-           macro_build (NULL, &icnt, NULL, "teq", "s,t,q", 0, 0, 7);
+           macro_build (NULL, "teq", "s,t,q", 0, 0, 7);
          else
-           macro_build (NULL, &icnt, NULL, "break", "c", 7);
+           macro_build (NULL, "break", "c", 7);
          return;
        }
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
          if (strcmp (s2, "mflo") == 0)
-           move_register (&icnt, dreg, sreg);
+           move_register (dreg, sreg);
          else
-           move_register (&icnt, dreg, 0);
+           move_register (dreg, 0);
          return;
        }
       if (imm_expr.X_op == O_constant
@@ -4698,17 +4794,16 @@ macro (struct mips_cl_insn *ip)
        {
          if (strcmp (s2, "mflo") == 0)
            {
-             macro_build (NULL, &icnt, NULL, dbl ? "dneg" : "neg", "d,w",
-                          dreg, sreg);
+             macro_build (NULL, dbl ? "dneg" : "neg", "d,w", dreg, sreg);
            }
          else
-           move_register (&icnt, dreg, 0);
+           move_register (dreg, 0);
          return;
        }
 
-      load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build (NULL, &icnt, NULL, s, "z,s,t", sreg, AT);
-      macro_build (NULL, &icnt, NULL, s2, "d", dreg);
+      load_register (AT, &imm_expr, dbl);
+      macro_build (NULL, s, "z,s,t", sreg, AT);
+      macro_build (NULL, s2, "d", dreg);
       break;
 
     case M_DIVU_3:
@@ -4732,8 +4827,8 @@ macro (struct mips_cl_insn *ip)
       mips_any_noreorder = 1;
       if (mips_trap)
        {
-         macro_build (NULL, &icnt, NULL, "teq", "s,t,q", treg, 0, 7);
-         macro_build (NULL, &icnt, NULL, s, "z,s,t", sreg, treg);
+         macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
+         macro_build (NULL, s, "z,s,t", sreg, treg);
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
          --mips_opts.noreorder;
@@ -4741,15 +4836,15 @@ macro (struct mips_cl_insn *ip)
       else
        {
          expr1.X_add_number = 8;
-         macro_build (NULL, &icnt, &expr1, "bne", "s,t,p", treg, 0);
-         macro_build (NULL, &icnt, NULL, s, "z,s,t", sreg, treg);
+         macro_build (&expr1, "bne", "s,t,p", treg, 0);
+         macro_build (NULL, s, "z,s,t", sreg, treg);
 
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
          --mips_opts.noreorder;
-         macro_build (NULL, &icnt, NULL, "break", "c", 7);
+         macro_build (NULL, "break", "c", 7);
        }
-      macro_build (NULL, &icnt, NULL, s2, "d", dreg);
+      macro_build (NULL, s2, "d", dreg);
       return;
 
     case M_DLCA_AB:
@@ -4774,7 +4869,7 @@ macro (struct mips_cl_insn *ip)
          && offset_expr.X_add_number >= -0x8000
          && offset_expr.X_add_number < 0x8000)
        {
-         macro_build (NULL, &icnt, &offset_expr,
+         macro_build (&offset_expr,
                       (dbl || HAVE_64BIT_ADDRESSES) ? "daddiu" : "addiu",
                       "t,r,j", treg, sreg, BFD_RELOC_LO16);
          return;
@@ -4791,50 +4886,6 @@ macro (struct mips_cl_insn *ip)
          used_at = 0;
        }
 
-      /* When generating embedded PIC code, we permit expressions of
-        the form
-          la   $treg,foo-bar
-          la   $treg,foo-bar($breg)
-        where bar is an address in the current section.  These are used
-        when getting the addresses of functions.  We don't permit
-        X_add_number to be non-zero, because if the symbol is
-        external the relaxing code needs to know that any addend is
-        purely the offset to X_op_symbol.  */
-      if (mips_pic == EMBEDDED_PIC
-         && offset_expr.X_op == O_subtract
-         && (symbol_constant_p (offset_expr.X_op_symbol)
-             ? S_GET_SEGMENT (offset_expr.X_op_symbol) == now_seg
-             : (symbol_equated_p (offset_expr.X_op_symbol)
-                && (S_GET_SEGMENT
-                    (symbol_get_value_expression (offset_expr.X_op_symbol)
-                     ->X_add_symbol)
-                    == now_seg)))
-         && (offset_expr.X_add_number == 0
-             || OUTPUT_FLAVOR == bfd_target_elf_flavour))
-       {
-         if (breg == 0)
-           {
-             tempreg = treg;
-             used_at = 0;
-             macro_build (NULL, &icnt, &offset_expr, "lui", "t,u", tempreg,
-                          BFD_RELOC_PCREL_HI16_S);
-           }
-         else
-           {
-             macro_build (NULL, &icnt, &offset_expr, "lui", "t,u", tempreg,
-                          BFD_RELOC_PCREL_HI16_S);
-             macro_build (NULL, &icnt, NULL,
-                          (dbl || HAVE_64BIT_ADDRESSES) ? "daddu" : "addu",
-                          "d,v,t", tempreg, tempreg, breg);
-           }
-         macro_build (NULL, &icnt, &offset_expr,
-                      (dbl || HAVE_64BIT_ADDRESSES) ? "daddiu" : "addiu",
-                      "t,r,j", treg, tempreg, BFD_RELOC_PCREL_LO16);
-         if (! used_at)
-           return;
-         break;
-       }
-
       if (offset_expr.X_op != O_symbol
          && offset_expr.X_op != O_constant)
        {
@@ -4843,8 +4894,8 @@ macro (struct mips_cl_insn *ip)
        }
 
       if (offset_expr.X_op == O_constant)
-       load_register (&icnt, tempreg, &offset_expr,
-                      ((mips_pic == EMBEDDED_PIC || mips_pic == NO_PIC)
+       load_register (tempreg, &offset_expr,
+                      (mips_pic == NO_PIC
                        ? (dbl || HAVE_64BIT_ADDRESSES)
                        : HAVE_64BIT_ADDRESSES));
       else if (mips_pic == NO_PIC)
@@ -4874,41 +4925,37 @@ macro (struct mips_cl_insn *ip)
              dsll      $tempreg,16
              daddiu    $tempreg,<sym>          (BFD_RELOC_LO16)
          */
-         char *p = NULL;
          if (HAVE_64BIT_ADDRESSES)
            {
-             /* We don't do GP optimization for now because RELAX_ENCODE can't
-                hold the data for such large chunks.  */
+             /* ??? We don't provide a GP-relative alternative for
+                these macros.  It used not to be possible with the
+                original relaxation code, but it could be done now.  */
 
              if (used_at == 0 && ! mips_opts.noat)
                {
-                 macro_build (p, &icnt, &offset_expr, "lui", "t,u",
+                 macro_build (&offset_expr, "lui", "t,u",
                               tempreg, BFD_RELOC_MIPS_HIGHEST);
-                 macro_build (p, &icnt, &offset_expr, "lui", "t,u",
+                 macro_build (&offset_expr, "lui", "t,u",
                               AT, BFD_RELOC_HI16_S);
-                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
+                 macro_build (&offset_expr, "daddiu", "t,r,j",
                               tempreg, tempreg, BFD_RELOC_MIPS_HIGHER);
-                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
+                 macro_build (&offset_expr, "daddiu", "t,r,j",
                               AT, AT, BFD_RELOC_LO16);
-                 macro_build (p, &icnt, NULL, "dsll32", "d,w,<",
-                              tempreg, tempreg, 0);
-                 macro_build (p, &icnt, NULL, "daddu", "d,v,t",
-                              tempreg, tempreg, AT);
+                 macro_build (NULL, "dsll32", "d,w,<", tempreg, tempreg, 0);
+                 macro_build (NULL, "daddu", "d,v,t", tempreg, tempreg, AT);
                  used_at = 1;
                }
              else
                {
-                 macro_build (p, &icnt, &offset_expr, "lui", "t,u",
+                 macro_build (&offset_expr, "lui", "t,u",
                               tempreg, BFD_RELOC_MIPS_HIGHEST);
-                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
+                 macro_build (&offset_expr, "daddiu", "t,r,j",
                               tempreg, tempreg, BFD_RELOC_MIPS_HIGHER);
-                 macro_build (p, &icnt, NULL, "dsll", "d,w,<",
-                              tempreg, tempreg, 16);
-                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
+                 macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
+                 macro_build (&offset_expr, "daddiu", "t,r,j",
                               tempreg, tempreg, BFD_RELOC_HI16_S);
-                 macro_build (p, &icnt, NULL, "dsll", "d,w,<",
-                              tempreg, tempreg, 16);
-                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
+                 macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
+                 macro_build (&offset_expr, "daddiu", "t,r,j",
                               tempreg, tempreg, BFD_RELOC_LO16);
                }
            }
@@ -4917,20 +4964,16 @@ macro (struct mips_cl_insn *ip)
              if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
                  && ! nopic_need_relax (offset_expr.X_add_symbol, 1))
                {
-                 frag_grow (20);
-                 macro_build (NULL, &icnt, &offset_expr, ADDRESS_ADDI_INSN,
-                              "t,r,j", tempreg, mips_gp_register,
-                              BFD_RELOC_GPREL16);
-                 p = frag_var (rs_machine_dependent, 8, 0,
-                               RELAX_ENCODE (4, 8, 0, 4, 0,
-                                             mips_opts.warn_about_macros),
-                               offset_expr.X_add_symbol, 0, NULL);
+                 relax_start (offset_expr.X_add_symbol);
+                 macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+                              tempreg, mips_gp_register, BFD_RELOC_GPREL16);
+                 relax_switch ();
                }
-             macro_build_lui (p, &icnt, &offset_expr, tempreg);
-             if (p != NULL)
-               p += 4;
-             macro_build (p, &icnt, &offset_expr, ADDRESS_ADDI_INSN,
-                          "t,r,j", tempreg, tempreg, BFD_RELOC_LO16);
+             macro_build_lui (&offset_expr, tempreg);
+             macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+                          tempreg, tempreg, BFD_RELOC_LO16);
+             if (mips_relax.sequence)
+               relax_end ();
            }
        }
       else if (mips_pic == SVR4_PIC && ! mips_big_got && ! HAVE_NEWABI)
@@ -4967,60 +5010,46 @@ macro (struct mips_cl_insn *ip)
             addiu instruction.
           */
 
-         expr1.X_add_number = offset_expr.X_add_number;
-         offset_expr.X_add_number = 0;
-         frag_grow (32);
-         if (expr1.X_add_number == 0 && breg == 0
-             && (call || tempreg == PIC_CALL_REG))
-           lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
-         macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
-                      tempreg, lw_reloc_type, mips_gp_register);
-         if (expr1.X_add_number == 0)
+         if (offset_expr.X_add_number == 0)
            {
-             int off;
-             char *p;
+             if (breg == 0 && (call || tempreg == PIC_CALL_REG))
+               lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
 
-             if (breg == 0)
-               off = 0;
-             else
+             relax_start (offset_expr.X_add_symbol);
+             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                          lw_reloc_type, mips_gp_register);
+             if (breg != 0)
                {
                  /* We're going to put in an addu instruction using
                     tempreg, so we may as well insert the nop right
                     now.  */
-                 macro_build (NULL, &icnt, NULL, "nop", "");
-                 off = 4;
+                 load_delay_nop ();
                }
-             p = frag_var (rs_machine_dependent, 8 - off, 0,
-                           RELAX_ENCODE (0, 8 - off, -4 - off, 4 - off, 0,
-                                         (breg == 0
-                                          ? mips_opts.warn_about_macros
-                                          : 0)),
-                           offset_expr.X_add_symbol, 0, NULL);
-             if (breg == 0)
-               {
-                 macro_build (p, &icnt, NULL, "nop", "");
-                 p += 4;
-               }
-             macro_build (p, &icnt, &expr1, ADDRESS_ADDI_INSN,
-                          "t,r,j", tempreg, tempreg, BFD_RELOC_LO16);
+             relax_switch ();
+             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+                          tempreg, BFD_RELOC_MIPS_GOT16, mips_gp_register);
+             load_delay_nop ();
+             macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+                          tempreg, tempreg, BFD_RELOC_LO16);
+             relax_end ();
              /* FIXME: If breg == 0, and the next instruction uses
                 $tempreg, then if this variant case is used an extra
                 nop will be generated.  */
            }
-         else if (expr1.X_add_number >= -0x8000
-                  && expr1.X_add_number < 0x8000)
+         else if (offset_expr.X_add_number >= -0x8000
+                  && offset_expr.X_add_number < 0x8000)
            {
-             macro_build (NULL, &icnt, NULL, "nop", "");
-             macro_build (NULL, &icnt, &expr1, ADDRESS_ADDI_INSN,
-                          "t,r,j", tempreg, tempreg, BFD_RELOC_LO16);
-             frag_var (rs_machine_dependent, 0, 0,
-                       RELAX_ENCODE (0, 0, -12, -4, 0, 0),
-                       offset_expr.X_add_symbol, 0, NULL);
+             load_got_offset (tempreg, &offset_expr);
+             load_delay_nop ();
+             add_got_offset (tempreg, &offset_expr);
            }
          else
            {
-             int off1;
-
+             expr1.X_add_number = offset_expr.X_add_number;
+             offset_expr.X_add_number =
+               ((offset_expr.X_add_number + 0x8000) & 0xffff) - 0x8000;
+             load_got_offset (tempreg, &offset_expr);
+             offset_expr.X_add_number = expr1.X_add_number;
              /* If we are going to add in a base register, and the
                 target register and the base register are the same,
                 then we are using AT as a temporary register.  Since
@@ -5028,40 +5057,21 @@ macro (struct mips_cl_insn *ip)
                 current AT (from the global offset table) and the
                 register into the register now, and pretend we were
                 not using a base register.  */
-             if (breg != treg)
-               off1 = 0;
-             else
+             if (breg == treg)
                {
-                 macro_build (NULL, &icnt, NULL, "nop", "");
-                 macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+                 load_delay_nop ();
+                 macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
                  breg = 0;
                  tempreg = treg;
-                 off1 = -8;
                }
-
-             /* Set mips_optimize around the lui instruction to avoid
-                inserting an unnecessary nop after the lw.  */
-             hold_mips_optimize = mips_optimize;
-             mips_optimize = 2;
-             macro_build_lui (NULL, &icnt, &expr1, AT);
-             mips_optimize = hold_mips_optimize;
-
-             macro_build (NULL, &icnt, &expr1, ADDRESS_ADDI_INSN, "t,r,j",
-                          AT, AT, BFD_RELOC_LO16);
-             macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                          tempreg, tempreg, AT);
-             frag_var (rs_machine_dependent, 0, 0,
-                       RELAX_ENCODE (0, 0, -16 + off1, -8, 0, 0),
-                       offset_expr.X_add_symbol, 0, NULL);
+             add_got_offset_hilo (tempreg, &offset_expr, AT);
              used_at = 1;
            }
        }
       else if (mips_pic == SVR4_PIC && ! mips_big_got && HAVE_NEWABI)
        {
-         char *p = NULL;
-         int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_DISP;
-         int adj = 0;
+         int add_breg_early = 0;
 
          /* If this is a reference to an external, and there is no
             constant, or local symbol (*), with or without a
@@ -5086,28 +5096,20 @@ macro (struct mips_cl_insn *ip)
             local symbols, even though it introduces an additional
             instruction.  */
 
-         frag_grow (28);
-         if (offset_expr.X_add_number == 0 && breg == 0
-             && (call || tempreg == PIC_CALL_REG))
-           lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
          if (offset_expr.X_add_number)
            {
-             frag_now->tc_frag_data.tc_fr_offset =
-               expr1.X_add_number = offset_expr.X_add_number;
+             expr1.X_add_number = offset_expr.X_add_number;
              offset_expr.X_add_number = 0;
 
-             macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
-                          "t,o(b)", tempreg, lw_reloc_type,
-                          mips_gp_register);
+             relax_start (offset_expr.X_add_symbol);
+             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                          BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
 
              if (expr1.X_add_number >= -0x8000
                  && expr1.X_add_number < 0x8000)
                {
-                 macro_build (NULL, &icnt, &expr1, ADDRESS_ADDI_INSN,
-                              "t,r,j", tempreg, tempreg, BFD_RELOC_LO16);
-                 p = frag_var (rs_machine_dependent, 4, 0,
-                               RELAX_ENCODE (8, 4, 0, 0, 0, 0),
-                               offset_expr.X_add_symbol, 0, NULL);
+                 macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
+                              tempreg, tempreg, BFD_RELOC_LO16);
                }
              else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
                {
@@ -5125,64 +5127,54 @@ macro (struct mips_cl_insn *ip)
                  else
                    {
                      assert (tempreg == AT);
-                     macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN,
-                                  "d,v,t", treg, AT, breg);
+                     macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+                                  treg, AT, breg);
                      dreg = treg;
-                     adj = 4;
+                     add_breg_early = 1;
                    }
 
-                 macro_build_lui (NULL, &icnt, &expr1, AT);
-                 macro_build (NULL, &icnt, &expr1, ADDRESS_ADDI_INSN,
-                              "t,r,j", AT, AT, BFD_RELOC_LO16);
-                 macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+                 load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
+                 macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               dreg, dreg, AT);
 
-                 p = frag_var (rs_machine_dependent, 4 + adj, 0,
-                               RELAX_ENCODE (16 + adj, 4 + adj,
-                                             0, 0, 0, 0),
-                               offset_expr.X_add_symbol, 0, NULL);
-
                  used_at = 1;
                }
              else
                as_bad (_("PIC code offset overflow (max 32 signed bits)"));
 
+             relax_switch ();
              offset_expr.X_add_number = expr1.X_add_number;
 
-             macro_build (p, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
-                          "t,o(b)", tempreg, BFD_RELOC_MIPS_GOT_DISP,
-                          mips_gp_register);
-             if (adj)
+             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                          BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
+             if (add_breg_early)
                {
-                 macro_build (p + 4, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+                 macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, tempreg, breg);
                  breg = 0;
                  tempreg = treg;
                }
+             relax_end ();
            }
-         else
+         else if (breg == 0 && (call || tempreg == PIC_CALL_REG))
            {
-             macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
-                          "t,o(b)", tempreg, lw_reloc_type,
-                          mips_gp_register);
-             if (lw_reloc_type != BFD_RELOC_MIPS_GOT_DISP)
-               p = frag_var (rs_machine_dependent, 0, 0,
-                             RELAX_ENCODE (0, 0, -4, 0, 0, 0),
-                             offset_expr.X_add_symbol, 0, NULL);
+             relax_start (offset_expr.X_add_symbol);
+             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                          BFD_RELOC_MIPS_CALL16, mips_gp_register);
+             relax_switch ();
+             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                          BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
+             relax_end ();
            }
-
-         if (! p)
+         else
            {
-             /* To avoid confusion in tc_gen_reloc, we must ensure
-                that this does not become a variant frag.  */
-             frag_wane (frag_now);
-             frag_new (0);
+             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                          BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
            }
        }
       else if (mips_pic == SVR4_PIC && ! HAVE_NEWABI)
        {
-         int gpdel;
-         char *p;
+         int gpdelay;
          int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
          int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
          int local_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
@@ -5230,63 +5222,39 @@ macro (struct mips_cl_insn *ip)
 
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
-         frag_grow (52);
-         if (reg_needs_delay (mips_gp_register))
-           gpdel = 4;
-         else
-           gpdel = 0;
+         relax_start (offset_expr.X_add_symbol);
+         gpdelay = reg_needs_delay (mips_gp_register);
          if (expr1.X_add_number == 0 && breg == 0
              && (call || tempreg == PIC_CALL_REG))
            {
              lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
              lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
            }
-         macro_build (NULL, &icnt, &offset_expr, "lui", "t,u",
-                      tempreg, lui_reloc_type);
-         macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+         macro_build (&offset_expr, "lui", "t,u", tempreg, lui_reloc_type);
+         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                       tempreg, tempreg, mips_gp_register);
-         macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                       tempreg, lw_reloc_type, tempreg);
          if (expr1.X_add_number == 0)
            {
-             int off;
-
-             if (breg == 0)
-               off = 0;
-             else
+             if (breg != 0)
                {
                  /* We're going to put in an addu instruction using
                     tempreg, so we may as well insert the nop right
                     now.  */
-                 macro_build (NULL, &icnt, NULL, "nop", "");
-                 off = 4;
+                 load_delay_nop ();
                }
-
-             p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
-                           RELAX_ENCODE (12 + off, 12 + gpdel, gpdel,
-                                         8 + gpdel, 0,
-                                         (breg == 0
-                                          ? mips_opts.warn_about_macros
-                                          : 0)),
-                           offset_expr.X_add_symbol, 0, NULL);
            }
          else if (expr1.X_add_number >= -0x8000
                   && expr1.X_add_number < 0x8000)
            {
-             macro_build (NULL, &icnt, NULL, "nop", "");
-             macro_build (NULL, &icnt, &expr1, ADDRESS_ADDI_INSN, "t,r,j",
+             load_delay_nop ();
+             macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
                           tempreg, tempreg, BFD_RELOC_LO16);
-
-             p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
-                           RELAX_ENCODE (20, 12 + gpdel, gpdel, 8 + gpdel, 0,
-                                         (breg == 0
-                                          ? mips_opts.warn_about_macros
-                                          : 0)),
-                           offset_expr.X_add_symbol, 0, NULL);
            }
          else
            {
-             int adj, dreg;
+             int dreg;
 
              /* If we are going to add in a base register, and the
                 target register and the base register are the same,
@@ -5296,61 +5264,40 @@ macro (struct mips_cl_insn *ip)
                 register into the register now, and pretend we were
                 not using a base register.  */
              if (breg != treg)
-               {
-                 adj = 0;
-                 dreg = tempreg;
-               }
+               dreg = tempreg;
              else
                {
                  assert (tempreg == AT);
-                 macro_build (NULL, &icnt, NULL, "nop", "");
-                 macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+                 load_delay_nop ();
+                 macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
                  dreg = treg;
-                 adj = 8;
                }
 
-             /* Set mips_optimize around the lui instruction to avoid
-                inserting an unnecessary nop after the lw.  */
-             hold_mips_optimize = mips_optimize;
-             mips_optimize = 2;
-             macro_build_lui (NULL, &icnt, &expr1, AT);
-             mips_optimize = hold_mips_optimize;
-
-             macro_build (NULL, &icnt, &expr1, ADDRESS_ADDI_INSN, "t,r,j",
-                          AT, AT, BFD_RELOC_LO16);
-             macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                          dreg, dreg, AT);
-
-             p = frag_var (rs_machine_dependent, 16 + gpdel + adj, 0,
-                           RELAX_ENCODE (24 + adj, 16 + gpdel + adj, gpdel,
-                                         8 + gpdel, 0,
-                                         (breg == 0
-                                          ? mips_opts.warn_about_macros
-                                          : 0)),
-                           offset_expr.X_add_symbol, 0, NULL);
+             load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
+             macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dreg, dreg, AT);
 
              used_at = 1;
            }
+         offset_expr.X_add_number =
+           ((expr1.X_add_number + 0x8000) & 0xffff) - 0x8000;
+         relax_switch ();
 
-         if (gpdel > 0)
+         if (gpdelay)
            {
              /* This is needed because this instruction uses $gp, but
                 the first instruction on the main stream does not.  */
-             macro_build (p, &icnt, NULL, "nop", "");
-             p += 4;
+             macro_build (NULL, "nop", "");
            }
 
-         macro_build (p, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
-                      tempreg, local_reloc_type, mips_gp_register);
-         p += 4;
+         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                      local_reloc_type, mips_gp_register);
          if (expr1.X_add_number >= -0x8000
              && expr1.X_add_number < 0x8000)
            {
-             macro_build (p, &icnt, NULL, "nop", "");
-             p += 4;
-             macro_build (p, &icnt, &expr1, ADDRESS_ADDI_INSN,
-                          "t,r,j", tempreg, tempreg, BFD_RELOC_LO16);
+             load_delay_nop ();
+             macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+                          tempreg, tempreg, BFD_RELOC_LO16);
              /* FIXME: If add_number is 0, and there was no base
                 register, the external symbol case ended with a load,
                 so if the symbol turns out to not be external, and
@@ -5364,33 +5311,28 @@ macro (struct mips_cl_insn *ip)
                  /* We must add in the base register now, as in the
                     external symbol case.  */
                  assert (tempreg == AT);
-                 macro_build (p, &icnt, NULL, "nop", "");
-                 p += 4;
-                 macro_build (p, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+                 load_delay_nop ();
+                 macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
-                 p += 4;
                  tempreg = treg;
                  /* We set breg to 0 because we have arranged to add
                     it in in both cases.  */
                  breg = 0;
                }
 
-             macro_build_lui (p, &icnt, &expr1, AT);
-             p += 4;
-             macro_build (p, &icnt, &expr1, ADDRESS_ADDI_INSN, "t,r,j",
+             macro_build_lui (&expr1, AT);
+             macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                           AT, AT, BFD_RELOC_LO16);
-             p += 4;
-             macro_build (p, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+             macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                           tempreg, tempreg, AT);
-             p += 4;
            }
+         relax_end ();
        }
       else if (mips_pic == SVR4_PIC && HAVE_NEWABI)
        {
-         char *p = NULL;
          int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
          int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
-         int adj = 0;
+         int add_breg_early = 0;
 
          /* This is the large GOT case.  If this is a reference to an
             external symbol, and there is no constant, we want
@@ -5423,10 +5365,9 @@ macro (struct mips_cl_insn *ip)
               addiu    $reg,$reg,<sym>         (BFD_RELOC_MIPS_GOT_OFST)
             otherwise we have to resort to GOT_HI16/GOT_LO16.  */
 
-         frag_grow (40);
+         relax_start (offset_expr.X_add_symbol);
 
-         frag_now->tc_frag_data.tc_fr_offset =
-           expr1.X_add_number = offset_expr.X_add_number;
+         expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
 
          if (expr1.X_add_number == 0 && breg == 0
@@ -5435,29 +5376,19 @@ macro (struct mips_cl_insn *ip)
              lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
              lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
            }
-         macro_build (NULL, &icnt, &offset_expr, "lui", "t,u",
-                      tempreg, lui_reloc_type);
-         macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+         macro_build (&offset_expr, "lui", "t,u", tempreg, lui_reloc_type);
+         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                       tempreg, tempreg, mips_gp_register);
-         macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
-                      "t,o(b)", tempreg, lw_reloc_type, tempreg);
+         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+                      tempreg, lw_reloc_type, tempreg);
 
          if (expr1.X_add_number == 0)
-           {
-             p = frag_var (rs_machine_dependent, 8, 0,
-                           RELAX_ENCODE (12, 8, 0, 4, 0,
-                                         mips_opts.warn_about_macros),
-                           offset_expr.X_add_symbol, 0, NULL);
-           }
+           ;
          else if (expr1.X_add_number >= -0x8000
                   && expr1.X_add_number < 0x8000)
            {
-             macro_build (NULL, &icnt, &expr1, ADDRESS_ADDI_INSN, "t,r,j",
+             macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
                           tempreg, tempreg, BFD_RELOC_LO16);
-             p = frag_var (rs_machine_dependent, 8, 0,
-                           RELAX_ENCODE (16, 8, 0, 4, 0,
-                                         mips_opts.warn_about_macros),
-                           offset_expr.X_add_symbol, 0, NULL);
            }
          else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
            {
@@ -5475,53 +5406,34 @@ macro (struct mips_cl_insn *ip)
              else
                {
                  assert (tempreg == AT);
-                 macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+                 macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
                  dreg = treg;
-                 adj = 4;
+                 add_breg_early = 1;
                }
 
-             /* Set mips_optimize around the lui instruction to avoid
-                inserting an unnecessary nop after the lw.  */
-             macro_build_lui (NULL, &icnt, &expr1, AT);
-             macro_build (NULL, &icnt, &expr1, ADDRESS_ADDI_INSN,
-                          "t,r,j", AT, AT, BFD_RELOC_LO16);
-             macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                          dreg, dreg, AT);
-
-             p = frag_var (rs_machine_dependent, 8 + adj, 0,
-                           RELAX_ENCODE (24 + adj, 8 + adj,
-                                         0, 4, 0,
-                                         (breg == 0
-                                          ? mips_opts.warn_about_macros
-                                          : 0)),
-                           offset_expr.X_add_symbol, 0, NULL);
+             load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
+             macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dreg, dreg, AT);
 
              used_at = 1;
            }
          else
            as_bad (_("PIC code offset overflow (max 32 signed bits)"));
 
+         relax_switch ();
          offset_expr.X_add_number = expr1.X_add_number;
-         macro_build (p, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
-                      tempreg, BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
-         macro_build (p + 4, &icnt, &offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
-                      tempreg, tempreg, BFD_RELOC_MIPS_GOT_OFST);
-         if (adj)
+         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                      BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
+         macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg,
+                      tempreg, BFD_RELOC_MIPS_GOT_OFST);
+         if (add_breg_early)
            {
-             macro_build (p + 8, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+             macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                           treg, tempreg, breg);
              breg = 0;
              tempreg = treg;
            }
-       }
-      else if (mips_pic == EMBEDDED_PIC)
-       {
-         /* We use
-              addiu    $tempreg,$gp,<sym>      (BFD_RELOC_GPREL16)
-            */
-         macro_build (NULL, &icnt, &offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
-                      tempreg, mips_gp_register, BFD_RELOC_GPREL16);
+         relax_end ();
        }
       else
        abort ();
@@ -5530,12 +5442,12 @@ macro (struct mips_cl_insn *ip)
        {
          char *s;
 
-         if (mips_pic == EMBEDDED_PIC || mips_pic == NO_PIC)
+         if (mips_pic == NO_PIC)
            s = (dbl || HAVE_64BIT_ADDRESSES) ? "daddu" : "addu";
          else
            s = ADDRESS_ADD_INSN;
 
-         macro_build (NULL, &icnt, NULL, s, "d,v,t", treg, tempreg, breg);
+         macro_build (NULL, s, "d,v,t", treg, tempreg, breg);
        }
 
       if (! used_at)
@@ -5548,9 +5460,9 @@ macro (struct mips_cl_insn *ip)
         requires an absolute address.  We convert it to a b
         instruction.  */
       if (mips_pic == NO_PIC)
-       macro_build (NULL, &icnt, &offset_expr, "j", "a");
+       macro_build (&offset_expr, "j", "a");
       else
-       macro_build (NULL, &icnt, &offset_expr, "b", "p");
+       macro_build (&offset_expr, "b", "p");
       return;
 
       /* The jal instructions must be handled as macros because when
@@ -5560,15 +5472,14 @@ macro (struct mips_cl_insn *ip)
       dreg = RA;
       /* Fall through.  */
     case M_JAL_2:
-      if (mips_pic == NO_PIC
-         || mips_pic == EMBEDDED_PIC)
-       macro_build (NULL, &icnt, NULL, "jalr", "d,s", dreg, sreg);
+      if (mips_pic == NO_PIC)
+       macro_build (NULL, "jalr", "d,s", dreg, sreg);
       else if (mips_pic == SVR4_PIC)
        {
          if (sreg != PIC_CALL_REG)
            as_warn (_("MIPS PIC call to register other than $25"));
 
-         macro_build (NULL, &icnt, NULL, "jalr", "d,s", dreg, sreg);
+         macro_build (NULL, "jalr", "d,s", dreg, sreg);
          if (! HAVE_NEWABI)
            {
              if (mips_cprestore_offset < 0)
@@ -5588,8 +5499,7 @@ macro (struct mips_cl_insn *ip)
                      mips_cprestore_valid = 1;
                    }
                  expr1.X_add_number = mips_cprestore_offset;
-                 macro_build_ldst_constoffset (NULL, &icnt, &expr1,
-                                               ADDRESS_LOAD_INSN,
+                 macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
                                                mips_gp_register,
                                                mips_frame_reg,
                                                HAVE_64BIT_ADDRESSES);
@@ -5603,11 +5513,9 @@ macro (struct mips_cl_insn *ip)
 
     case M_JAL_A:
       if (mips_pic == NO_PIC)
-       macro_build (NULL, &icnt, &offset_expr, "jal", "a");
+       macro_build (&offset_expr, "jal", "a");
       else if (mips_pic == SVR4_PIC)
        {
-         char *p;
-
          /* If this is a reference to an external symbol, and we are
             using a small GOT, we want
               lw       $25,<sym>($gp)          (BFD_RELOC_MIPS_CALL16)
@@ -5640,86 +5548,74 @@ macro (struct mips_cl_insn *ip)
            {
              if (! mips_big_got)
                {
-                 frag_grow (4);
-                 macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
-                              "t,o(b)", PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
+                 relax_start (offset_expr.X_add_symbol);
+                 macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+                              PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
+                              mips_gp_register);
+                 relax_switch ();
+                 macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+                              PIC_CALL_REG, BFD_RELOC_MIPS_GOT_DISP,
                               mips_gp_register);
-                 frag_var (rs_machine_dependent, 0, 0,
-                           RELAX_ENCODE (0, 0, -4, 0, 0, 0),
-                           offset_expr.X_add_symbol, 0, NULL);
+                 relax_end ();
                }
              else
                {
-                 frag_grow (20);
-                 macro_build (NULL, &icnt, &offset_expr, "lui", "t,u",
-                              PIC_CALL_REG, BFD_RELOC_MIPS_CALL_HI16);
-                 macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                              PIC_CALL_REG, PIC_CALL_REG, mips_gp_register);
-                 macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
-                              "t,o(b)", PIC_CALL_REG,
-                              BFD_RELOC_MIPS_CALL_LO16, PIC_CALL_REG);
-                 p = frag_var (rs_machine_dependent, 8, 0,
-                               RELAX_ENCODE (12, 8, 0, 4, 0, 0),
-                               offset_expr.X_add_symbol, 0, NULL);
-                 macro_build (p, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
-                              "t,o(b)", PIC_CALL_REG,
-                              BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
-                 macro_build (p + 4, &icnt, &offset_expr, ADDRESS_ADDI_INSN,
-                              "t,r,j", PIC_CALL_REG, PIC_CALL_REG,
+                 relax_start (offset_expr.X_add_symbol);
+                 macro_build (&offset_expr, "lui", "t,u", PIC_CALL_REG,
+                              BFD_RELOC_MIPS_CALL_HI16);
+                 macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", PIC_CALL_REG,
+                              PIC_CALL_REG, mips_gp_register);
+                 macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+                              PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
+                              PIC_CALL_REG);
+                 relax_switch ();
+                 macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+                              PIC_CALL_REG, BFD_RELOC_MIPS_GOT_PAGE,
+                              mips_gp_register);
+                 macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+                              PIC_CALL_REG, PIC_CALL_REG,
                               BFD_RELOC_MIPS_GOT_OFST);
+                 relax_end ();
                }
 
-             macro_build_jalr (icnt, &offset_expr);
+             macro_build_jalr (&offset_expr);
            }
          else
            {
-             frag_grow (40);
+             relax_start (offset_expr.X_add_symbol);
              if (! mips_big_got)
                {
-                 macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
-                              "t,o(b)", PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
+                 macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+                              PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
                               mips_gp_register);
-                 macro_build (NULL, &icnt, NULL, "nop", "");
-                 p = frag_var (rs_machine_dependent, 4, 0,
-                               RELAX_ENCODE (0, 4, -8, 0, 0, 0),
-                               offset_expr.X_add_symbol, 0, NULL);
+                 load_delay_nop ();
+                 relax_switch ();
                }
              else
                {
-                 int gpdel;
-
-                 if (reg_needs_delay (mips_gp_register))
-                   gpdel = 4;
-                 else
-                   gpdel = 0;
-                 macro_build (NULL, &icnt, &offset_expr, "lui", "t,u",
-                              PIC_CALL_REG, BFD_RELOC_MIPS_CALL_HI16);
-                 macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                              PIC_CALL_REG, PIC_CALL_REG, mips_gp_register);
-                 macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
-                              "t,o(b)", PIC_CALL_REG,
-                              BFD_RELOC_MIPS_CALL_LO16, PIC_CALL_REG);
-                 macro_build (NULL, &icnt, NULL, "nop", "");
-                 p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
-                               RELAX_ENCODE (16, 12 + gpdel, gpdel,
-                                             8 + gpdel, 0, 0),
-                               offset_expr.X_add_symbol, 0, NULL);
-                 if (gpdel > 0)
-                   {
-                     macro_build (p, &icnt, NULL, "nop", "");
-                     p += 4;
-                   }
-                 macro_build (p, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
-                              "t,o(b)", PIC_CALL_REG, BFD_RELOC_MIPS_GOT16,
-                              mips_gp_register);
-                 p += 4;
-                 macro_build (p, &icnt, NULL, "nop", "");
-                 p += 4;
+                 int gpdelay;
+
+                 gpdelay = reg_needs_delay (mips_gp_register);
+                 macro_build (&offset_expr, "lui", "t,u", PIC_CALL_REG,
+                              BFD_RELOC_MIPS_CALL_HI16);
+                 macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", PIC_CALL_REG,
+                              PIC_CALL_REG, mips_gp_register);
+                 macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+                              PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
+                              PIC_CALL_REG);
+                 load_delay_nop ();
+                 relax_switch ();
+                 if (gpdelay)
+                   macro_build (NULL, "nop", "");
                }
-             macro_build (p, &icnt, &offset_expr, ADDRESS_ADDI_INSN,
-                          "t,r,j", PIC_CALL_REG, PIC_CALL_REG,
-                          BFD_RELOC_LO16);
-             macro_build_jalr (icnt, &offset_expr);
+             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+                          PIC_CALL_REG, BFD_RELOC_MIPS_GOT16,
+                          mips_gp_register);
+             load_delay_nop ();
+             macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+                          PIC_CALL_REG, PIC_CALL_REG, BFD_RELOC_LO16);
+             relax_end ();
+             macro_build_jalr (&offset_expr);
 
              if (mips_cprestore_offset < 0)
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
@@ -5738,23 +5634,15 @@ macro (struct mips_cl_insn *ip)
                      mips_cprestore_valid = 1;
                    }
                  if (mips_opts.noreorder)
-                   macro_build (NULL, &icnt, NULL, "nop", "");
+                   macro_build (NULL, "nop", "");
                  expr1.X_add_number = mips_cprestore_offset;
-                 macro_build_ldst_constoffset (NULL, &icnt, &expr1,
-                                               ADDRESS_LOAD_INSN,
+                 macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
                                                mips_gp_register,
                                                mips_frame_reg,
                                                HAVE_64BIT_ADDRESSES);
                }
            }
        }
-      else if (mips_pic == EMBEDDED_PIC)
-       {
-         macro_build (NULL, &icnt, &offset_expr, "bal", "p");
-         /* The linker may expand the call to a longer sequence which
-            uses $at, so we must break rather than return.  */
-         break;
-       }
       else
        abort ();
 
@@ -5950,46 +5838,6 @@ macro (struct mips_cl_insn *ip)
                                       ^ 0x80000000) - 0x80000000);
        }
 
-      /* For embedded PIC, we allow loads where the offset is calculated
-         by subtracting a symbol in the current segment from an unknown
-         symbol, relative to a base register, e.g.:
-               <op>    $treg, <sym>-<localsym>($breg)
-        This is used by the compiler for switch statements.  */
-      if (mips_pic == EMBEDDED_PIC
-          && offset_expr.X_op == O_subtract
-          && (symbol_constant_p (offset_expr.X_op_symbol)
-              ? S_GET_SEGMENT (offset_expr.X_op_symbol) == now_seg
-              : (symbol_equated_p (offset_expr.X_op_symbol)
-                 && (S_GET_SEGMENT
-                     (symbol_get_value_expression (offset_expr.X_op_symbol)
-                      ->X_add_symbol)
-                     == now_seg)))
-          && breg != 0
-          && (offset_expr.X_add_number == 0
-              || OUTPUT_FLAVOR == bfd_target_elf_flavour))
-        {
-          /* For this case, we output the instructions:
-                lui     $tempreg,<sym>          (BFD_RELOC_PCREL_HI16_S)
-                addiu   $tempreg,$tempreg,$breg
-                <op>    $treg,<sym>($tempreg)   (BFD_RELOC_PCREL_LO16)
-             If the relocation would fit entirely in 16 bits, it would be
-             nice to emit:
-                <op>    $treg,<sym>($breg)      (BFD_RELOC_PCREL_LO16)
-             instead, but that seems quite difficult.  */
-          macro_build (NULL, &icnt, &offset_expr, "lui", "t,u", tempreg,
-                      BFD_RELOC_PCREL_HI16_S);
-          macro_build (NULL, &icnt, NULL,
-                       ((bfd_arch_bits_per_address (stdoutput) == 32
-                         || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
-                        ? "addu" : "daddu"),
-                       "d,v,t", tempreg, tempreg, breg);
-          macro_build (NULL, &icnt, &offset_expr, s, fmt, treg,
-                       BFD_RELOC_PCREL_LO16, tempreg);
-          if (! used_at)
-            return;
-          break;
-        }
-
       if (offset_expr.X_op != O_constant
          && offset_expr.X_op != O_symbol)
        {
@@ -6002,8 +5850,6 @@ macro (struct mips_cl_insn *ip)
       if (mips_pic == NO_PIC
          || offset_expr.X_op == O_constant)
        {
-         char *p;
-
          /* If this is a reference to a GP relative symbol, and there
             is no base register, we want
               <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
@@ -6089,46 +5935,40 @@ macro (struct mips_cl_insn *ip)
                  && offset_expr.X_op == O_constant
                  && ! IS_SEXT_32BIT_NUM (offset_expr.X_add_number + 0x8000)))
            {
-             p = NULL;
-
-             /* We don't do GP optimization for now because RELAX_ENCODE can't
-                hold the data for such large chunks.  */
+             /* ??? We don't provide a GP-relative alternative for
+                these macros.  It used not to be possible with the
+                original relaxation code, but it could be done now.  */
 
              if (used_at == 0 && ! mips_opts.noat)
                {
-                 macro_build (p, &icnt, &offset_expr, "lui", "t,u",
-                              tempreg, BFD_RELOC_MIPS_HIGHEST);
-                 macro_build (p, &icnt, &offset_expr, "lui", "t,u",
-                              AT, BFD_RELOC_HI16_S);
-                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
-                              tempreg, tempreg, BFD_RELOC_MIPS_HIGHER);
+                 macro_build (&offset_expr, "lui", "t,u", tempreg,
+                              BFD_RELOC_MIPS_HIGHEST);
+                 macro_build (&offset_expr, "lui", "t,u", AT,
+                              BFD_RELOC_HI16_S);
+                 macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
+                              tempreg, BFD_RELOC_MIPS_HIGHER);
                  if (breg != 0)
-                   macro_build (p, &icnt, NULL, "daddu", "d,v,t",
-                                AT, AT, breg);
-                 macro_build (p, &icnt, NULL, "dsll32", "d,w,<",
-                              tempreg, tempreg, 0);
-                 macro_build (p, &icnt, NULL, "daddu", "d,v,t",
-                              tempreg, tempreg, AT);
-                 macro_build (p, &icnt, &offset_expr, s, fmt, treg,
-                              BFD_RELOC_LO16, tempreg);
+                   macro_build (NULL, "daddu", "d,v,t", AT, AT, breg);
+                 macro_build (NULL, "dsll32", "d,w,<", tempreg, tempreg, 0);
+                 macro_build (NULL, "daddu", "d,v,t", tempreg, tempreg, AT);
+                 macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16,
+                              tempreg);
                  used_at = 1;
                }
              else
                {
-                 macro_build (p, &icnt, &offset_expr, "lui", "t,u",
-                              tempreg, BFD_RELOC_MIPS_HIGHEST);
-                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
-                              tempreg, tempreg, BFD_RELOC_MIPS_HIGHER);
-                 macro_build (p, &icnt, NULL, "dsll", "d,w,<",
-                              tempreg, tempreg, 16);
-                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
-                              tempreg, tempreg, BFD_RELOC_HI16_S);
-                 macro_build (p, &icnt, NULL, "dsll", "d,w,<",
-                              tempreg, tempreg, 16);
+                 macro_build (&offset_expr, "lui", "t,u", tempreg,
+                              BFD_RELOC_MIPS_HIGHEST);
+                 macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
+                              tempreg, BFD_RELOC_MIPS_HIGHER);
+                 macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
+                 macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
+                              tempreg, BFD_RELOC_HI16_S);
+                 macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
                  if (breg != 0)
-                   macro_build (p, &icnt, NULL, "daddu", "d,v,t",
+                   macro_build (NULL, "daddu", "d,v,t",
                                 tempreg, tempreg, breg);
-                 macro_build (p, &icnt, &offset_expr, s, fmt, treg,
+                 macro_build (&offset_expr, s, fmt, treg,
                               BFD_RELOC_LO16, tempreg);
                }
 
@@ -6141,58 +5981,44 @@ macro (struct mips_cl_insn *ip)
 
          if (breg == 0)
            {
-             if ((valueT) offset_expr.X_add_number > MAX_GPREL_OFFSET
-                 || nopic_need_relax (offset_expr.X_add_symbol, 1))
-               p = NULL;
-             else
+             if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
+                 && ! nopic_need_relax (offset_expr.X_add_symbol, 1))
                {
-                 frag_grow (20);
-                 macro_build (NULL, &icnt, &offset_expr, s, fmt, treg,
-                              BFD_RELOC_GPREL16, mips_gp_register);
-                 p = frag_var (rs_machine_dependent, 8, 0,
-                               RELAX_ENCODE (4, 8, 0, 4, 0,
-                                             (mips_opts.warn_about_macros
-                                              || (used_at
-                                                  && mips_opts.noat))),
-                               offset_expr.X_add_symbol, 0, NULL);
+                 relax_start (offset_expr.X_add_symbol);
+                 macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_GPREL16,
+                              mips_gp_register);
+                 relax_switch ();
                  used_at = 0;
                }
-             macro_build_lui (p, &icnt, &offset_expr, tempreg);
-             if (p != NULL)
-               p += 4;
-             macro_build (p, &icnt, &offset_expr, s, fmt, treg,
+             macro_build_lui (&offset_expr, tempreg);
+             macro_build (&offset_expr, s, fmt, treg,
                           BFD_RELOC_LO16, tempreg);
+             if (mips_relax.sequence)
+               relax_end ();
            }
          else
            {
-             if ((valueT) offset_expr.X_add_number > MAX_GPREL_OFFSET
-                 || nopic_need_relax (offset_expr.X_add_symbol, 1))
-               p = NULL;
-             else
+             if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
+                 && ! nopic_need_relax (offset_expr.X_add_symbol, 1))
                {
-                 frag_grow (28);
-                 macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+                 relax_start (offset_expr.X_add_symbol);
+                 macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               tempreg, breg, mips_gp_register);
-                 macro_build (NULL, &icnt, &offset_expr, s, fmt, treg,
+                 macro_build (&offset_expr, s, fmt, treg,
                               BFD_RELOC_GPREL16, tempreg);
-                 p = frag_var (rs_machine_dependent, 12, 0,
-                               RELAX_ENCODE (8, 12, 0, 8, 0, 0),
-                               offset_expr.X_add_symbol, 0, NULL);
+                 relax_switch ();
                }
-             macro_build_lui (p, &icnt, &offset_expr, tempreg);
-             if (p != NULL)
-               p += 4;
-             macro_build (p, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+             macro_build_lui (&offset_expr, tempreg);
+             macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                           tempreg, tempreg, breg);
-             if (p != NULL)
-               p += 4;
-             macro_build (p, &icnt, &offset_expr, s, fmt, treg,
+             macro_build (&offset_expr, s, fmt, treg,
                           BFD_RELOC_LO16, tempreg);
+             if (mips_relax.sequence)
+               relax_end ();
            }
        }
       else if (mips_pic == SVR4_PIC && ! mips_big_got)
        {
-         char *p;
          int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
 
          /* If this is a reference to an external symbol, we want
@@ -6218,13 +6044,12 @@ macro (struct mips_cl_insn *ip)
          assert (offset_expr.X_op == O_symbol);
          if (HAVE_NEWABI)
            {
-             macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
-                          "t,o(b)", tempreg, BFD_RELOC_MIPS_GOT_PAGE,
-                          mips_gp_register);
+             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                          BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
              if (breg != 0)
-               macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+               macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                             tempreg, tempreg, breg);
-             macro_build (NULL, &icnt, &offset_expr, s, fmt, treg,
+             macro_build (&offset_expr, s, fmt, treg,
                           BFD_RELOC_MIPS_GOT_OFST, tempreg);
 
              if (! used_at)
@@ -6237,25 +6062,22 @@ macro (struct mips_cl_insn *ip)
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
-         frag_grow (20);
-         macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
-                      tempreg, lw_reloc_type, mips_gp_register);
-         macro_build (NULL, &icnt, NULL, "nop", "");
-         p = frag_var (rs_machine_dependent, 4, 0,
-                       RELAX_ENCODE (0, 4, -8, 0, 0, 0),
-                       offset_expr.X_add_symbol, 0, NULL);
-         macro_build (p, &icnt, &offset_expr, ADDRESS_ADDI_INSN,
-                      "t,r,j", tempreg, tempreg, BFD_RELOC_LO16);
+         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                      lw_reloc_type, mips_gp_register);
+         load_delay_nop ();
+         relax_start (offset_expr.X_add_symbol);
+         relax_switch ();
+         macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg,
+                      tempreg, BFD_RELOC_LO16);
+         relax_end ();
          if (breg != 0)
-           macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                         tempreg, tempreg, breg);
-         macro_build (NULL, &icnt, &expr1, s, fmt, treg, BFD_RELOC_LO16,
-                      tempreg);
+         macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
        }
       else if (mips_pic == SVR4_PIC && ! HAVE_NEWABI)
        {
-         int gpdel;
-         char *p;
+         int gpdelay;
 
          /* If this is a reference to an external symbol, we want
               lui      $tempreg,<sym>          (BFD_RELOC_MIPS_GOT_HI16)
@@ -6279,43 +6101,31 @@ macro (struct mips_cl_insn *ip)
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
-         if (reg_needs_delay (mips_gp_register))
-           gpdel = 4;
-         else
-           gpdel = 0;
-         frag_grow (36);
-         macro_build (NULL, &icnt, &offset_expr, "lui", "t,u", tempreg,
+         gpdelay = reg_needs_delay (mips_gp_register);
+         relax_start (offset_expr.X_add_symbol);
+         macro_build (&offset_expr, "lui", "t,u", tempreg,
                       BFD_RELOC_MIPS_GOT_HI16);
-         macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                      tempreg, tempreg, mips_gp_register);
-         macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
-                      tempreg, BFD_RELOC_MIPS_GOT_LO16, tempreg);
-         p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
-                       RELAX_ENCODE (12, 12 + gpdel, gpdel, 8 + gpdel, 0, 0),
-                       offset_expr.X_add_symbol, 0, NULL);
-         if (gpdel > 0)
-           {
-             macro_build (p, &icnt, NULL, "nop", "");
-             p += 4;
-           }
-         macro_build (p, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
-                      tempreg, BFD_RELOC_MIPS_GOT16, mips_gp_register);
-         p += 4;
-         macro_build (p, &icnt, NULL, "nop", "");
-         p += 4;
-         macro_build (p, &icnt, &offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
-                      tempreg, tempreg, BFD_RELOC_LO16);
+         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg,
+                      mips_gp_register);
+         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                      BFD_RELOC_MIPS_GOT_LO16, tempreg);
+         relax_switch ();
+         if (gpdelay)
+           macro_build (NULL, "nop", "");
+         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                      BFD_RELOC_MIPS_GOT16, mips_gp_register);
+         load_delay_nop ();
+         macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg,
+                      tempreg, BFD_RELOC_LO16);
+         relax_end ();
+
          if (breg != 0)
-           macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                         tempreg, tempreg, breg);
-         macro_build (NULL, &icnt, &expr1, s, fmt, treg, BFD_RELOC_LO16,
-                      tempreg);
+         macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
        }
       else if (mips_pic == SVR4_PIC && HAVE_NEWABI)
        {
-         char *p;
-         int bregsz = breg != 0 ? 4 : 0;
-
          /* If this is a reference to an external symbol, we want
               lui      $tempreg,<sym>          (BFD_RELOC_MIPS_GOT_HI16)
               add      $tempreg,$tempreg,$gp
@@ -6325,60 +6135,33 @@ macro (struct mips_cl_insn *ip)
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT_PAGE)
               <op>     $treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GOT_OFST)  */
          assert (offset_expr.X_op == O_symbol);
-         frag_grow (36);
-         frag_now->tc_frag_data.tc_fr_offset =
-           expr1.X_add_number = offset_expr.X_add_number;
+         expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
-         macro_build (NULL, &icnt, &offset_expr, "lui", "t,u", tempreg,
+         relax_start (offset_expr.X_add_symbol);
+         macro_build (&offset_expr, "lui", "t,u", tempreg,
                       BFD_RELOC_MIPS_GOT_HI16);
-         macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                      tempreg, tempreg, mips_gp_register);
-         macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
-                      tempreg, BFD_RELOC_MIPS_GOT_LO16, tempreg);
+         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg,
+                      mips_gp_register);
+         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                      BFD_RELOC_MIPS_GOT_LO16, tempreg);
          if (breg != 0)
-           macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                         tempreg, tempreg, breg);
-         macro_build (NULL, &icnt, &expr1, s, fmt, treg, BFD_RELOC_LO16,
-                      tempreg);
+         macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
 
+         relax_switch ();
          offset_expr.X_add_number = expr1.X_add_number;
-         p = frag_var (rs_machine_dependent, 12 + bregsz, 0,
-                       RELAX_ENCODE (16 + bregsz, 8 + bregsz,
-                                     0, 4 + bregsz, 0, 0),
-                       offset_expr.X_add_symbol, 0, NULL);
-         macro_build (p, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
-                      tempreg, BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
+         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+                      BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
          if (breg != 0)
-           macro_build (p + 4, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                         tempreg, tempreg, breg);
-         macro_build (p + 4 + bregsz, &icnt, &offset_expr, s, fmt, treg,
+         macro_build (&offset_expr, s, fmt, treg,
                       BFD_RELOC_MIPS_GOT_OFST, tempreg);
-       }
-      else if (mips_pic == EMBEDDED_PIC)
-       {
-         /* If there is no base register, we want
-              <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
-            If there is a base register, we want
-              addu     $tempreg,$breg,$gp
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_GPREL16)
-            */
-         assert (offset_expr.X_op == O_symbol);
-         if (breg == 0)
-           {
-             macro_build (NULL, &icnt, &offset_expr, s, fmt, treg,
-                          BFD_RELOC_GPREL16, mips_gp_register);
-             used_at = 0;
-           }
-         else
-           {
-             macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                          tempreg, breg, mips_gp_register);
-             macro_build (NULL, &icnt, &offset_expr, s, fmt, treg,
-                          BFD_RELOC_GPREL16, tempreg);
-           }
+         relax_end ();
        }
       else
        abort ();
@@ -6390,18 +6173,18 @@ macro (struct mips_cl_insn *ip)
 
     case M_LI:
     case M_LI_S:
-      load_register (&icnt, treg, &imm_expr, 0);
+      load_register (treg, &imm_expr, 0);
       return;
 
     case M_DLI:
-      load_register (&icnt, treg, &imm_expr, 1);
+      load_register (treg, &imm_expr, 1);
       return;
 
     case M_LI_SS:
       if (imm_expr.X_op == O_constant)
        {
-         load_register (&icnt, AT, &imm_expr, 0);
-         macro_build (NULL, &icnt, NULL, "mtc1", "t,G", AT, treg);
+         load_register (AT, &imm_expr, 0);
+         macro_build (NULL, "mtc1", "t,G", AT, treg);
          break;
        }
       else
@@ -6411,7 +6194,7 @@ macro (struct mips_cl_insn *ip)
                                           (offset_expr.X_add_symbol)),
                             ".lit4") == 0
                  && offset_expr.X_add_number == 0);
-         macro_build (NULL, &icnt, &offset_expr, "lwc1", "T,o(b)", treg,
+         macro_build (&offset_expr, "lwc1", "T,o(b)", treg,
                       BFD_RELOC_MIPS_LITERAL, mips_gp_register);
          return;
        }
@@ -6424,7 +6207,7 @@ macro (struct mips_cl_insn *ip)
       if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
        {
          if (HAVE_64BIT_GPRS)
-           load_register (&icnt, treg, &imm_expr, 1);
+           load_register (treg, &imm_expr, 1);
          else
            {
              int hreg, lreg;
@@ -6441,15 +6224,15 @@ macro (struct mips_cl_insn *ip)
                }
 
              if (hreg <= 31)
-               load_register (&icnt, hreg, &imm_expr, 0);
+               load_register (hreg, &imm_expr, 0);
              if (lreg <= 31)
                {
                  if (offset_expr.X_op == O_absent)
-                   move_register (&icnt, lreg, 0);
+                   move_register (lreg, 0);
                  else
                    {
                      assert (offset_expr.X_op == O_constant);
-                     load_register (&icnt, lreg, &offset_expr, 0);
+                     load_register (lreg, &offset_expr, 0);
                    }
                }
            }
@@ -6460,48 +6243,31 @@ macro (struct mips_cl_insn *ip)
         upper 16 bits of the address.  */
       if (mips_pic == NO_PIC)
        {
-         macro_build_lui (NULL, &icnt, &offset_expr, AT);
+         macro_build_lui (&offset_expr, AT);
        }
       else if (mips_pic == SVR4_PIC)
        {
-         macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
-                      AT, BFD_RELOC_MIPS_GOT16, mips_gp_register);
-       }
-      else if (mips_pic == EMBEDDED_PIC)
-       {
-         /* For embedded PIC we pick up the entire address off $gp in
-            a single instruction.  */
-         macro_build (NULL, &icnt, &offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
-                      AT, mips_gp_register, BFD_RELOC_GPREL16);
-         offset_expr.X_op = O_constant;
-         offset_expr.X_add_number = 0;
+         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
+                      BFD_RELOC_MIPS_GOT16, mips_gp_register);
        }
       else
        abort ();
 
       /* Now we load the register(s).  */
       if (HAVE_64BIT_GPRS)
-       macro_build (NULL, &icnt, &offset_expr, "ld", "t,o(b)", treg,
-                    BFD_RELOC_LO16, AT);
+       macro_build (&offset_expr, "ld", "t,o(b)", treg, BFD_RELOC_LO16, AT);
       else
        {
-         macro_build (NULL, &icnt, &offset_expr, "lw", "t,o(b)", treg,
-                      BFD_RELOC_LO16, AT);
+         macro_build (&offset_expr, "lw", "t,o(b)", treg, BFD_RELOC_LO16, AT);
          if (treg != RA)
            {
              /* FIXME: How in the world do we deal with the possible
                 overflow here?  */
              offset_expr.X_add_number += 4;
-             macro_build (NULL, &icnt, &offset_expr, "lw", "t,o(b)",
+             macro_build (&offset_expr, "lw", "t,o(b)",
                           treg + 1, BFD_RELOC_LO16, AT);
            }
        }
-
-      /* To avoid confusion in tc_gen_reloc, we must ensure that this
-        does not become a variant frag.  */
-      frag_wane (frag_now);
-      frag_new (0);
-
       break;
 
     case M_LI_DD:
@@ -6512,22 +6278,22 @@ macro (struct mips_cl_insn *ip)
          OFFSET_EXPR.  */
       if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
        {
-         load_register (&icnt, AT, &imm_expr, HAVE_64BIT_FPRS);
+         load_register (AT, &imm_expr, HAVE_64BIT_FPRS);
          if (HAVE_64BIT_FPRS)
            {
              assert (HAVE_64BIT_GPRS);
-             macro_build (NULL, &icnt, NULL, "dmtc1", "t,S", AT, treg);
+             macro_build (NULL, "dmtc1", "t,S", AT, treg);
            }
          else
            {
-             macro_build (NULL, &icnt, NULL, "mtc1", "t,G", AT, treg + 1);
+             macro_build (NULL, "mtc1", "t,G", AT, treg + 1);
              if (offset_expr.X_op == O_absent)
-               macro_build (NULL, &icnt, NULL, "mtc1", "t,G", 0, treg);
+               macro_build (NULL, "mtc1", "t,G", 0, treg);
              else
                {
                  assert (offset_expr.X_op == O_constant);
-                 load_register (&icnt, AT, &offset_expr, 0);
-                 macro_build (NULL, &icnt, NULL, "mtc1", "t,G", AT, treg);
+                 load_register (AT, &offset_expr, 0);
+                 macro_build (NULL, "mtc1", "t,G", AT, treg);
                }
            }
          break;
@@ -6540,7 +6306,7 @@ macro (struct mips_cl_insn *ip)
        {
          if (mips_opts.isa != ISA_MIPS1)
            {
-             macro_build (NULL, &icnt, &offset_expr, "ldc1", "T,o(b)", treg,
+             macro_build (&offset_expr, "ldc1", "T,o(b)", treg,
                           BFD_RELOC_MIPS_LITERAL, mips_gp_register);
              return;
            }
@@ -6552,25 +6318,18 @@ macro (struct mips_cl_insn *ip)
        {
          assert (strcmp (s, RDATA_SECTION_NAME) == 0);
          if (mips_pic == SVR4_PIC)
-           macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
-                        "t,o(b)", AT, BFD_RELOC_MIPS_GOT16,
-                        mips_gp_register);
+           macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
+                        BFD_RELOC_MIPS_GOT16, mips_gp_register);
          else
            {
              /* FIXME: This won't work for a 64 bit address.  */
-             macro_build_lui (NULL, &icnt, &offset_expr, AT);
+             macro_build_lui (&offset_expr, AT);
            }
 
          if (mips_opts.isa != ISA_MIPS1)
-           {
-             macro_build (NULL, &icnt, &offset_expr, "ldc1", "T,o(b)", treg,
-                          BFD_RELOC_LO16, AT);
-
-             /* To avoid confusion in tc_gen_reloc, we must ensure
-                that this does not become a variant frag.  */
-             frag_wane (frag_now);
-             frag_new (0);
-
+           {
+             macro_build (&offset_expr, "ldc1", "T,o(b)",
+                          treg, BFD_RELOC_LO16, AT);
              break;
            }
          breg = AT;
@@ -6589,19 +6348,14 @@ macro (struct mips_cl_insn *ip)
       r = BFD_RELOC_LO16;
     dob:
       assert (mips_opts.isa == ISA_MIPS1);
-      macro_build (NULL, &icnt, &offset_expr, "lwc1", "T,o(b)",
+      macro_build (&offset_expr, "lwc1", "T,o(b)",
                   target_big_endian ? treg + 1 : treg, r, breg);
       /* FIXME: A possible overflow which I don't know how to deal
         with.  */
       offset_expr.X_add_number += 4;
-      macro_build (NULL, &icnt, &offset_expr, "lwc1", "T,o(b)",
+      macro_build (&offset_expr, "lwc1", "T,o(b)",
                   target_big_endian ? treg : treg + 1, r, breg);
 
-      /* To avoid confusion in tc_gen_reloc, we must ensure that this
-        does not become a variant frag.  */
-      frag_wane (frag_now);
-      frag_new (0);
-
       if (breg != AT)
        return;
       break;
@@ -6676,11 +6430,6 @@ macro (struct mips_cl_insn *ip)
       fmt = "t,o(b)";
 
     ldd_std:
-      /* We do _not_ bother to allow embedded PIC (symbol-local_symbol)
-        loads for the case of doing a pair of loads to simulate an 'ld'.
-        This is not currently done by the compiler, and assembly coders
-        writing embedded-pic code can cope.  */
-
       if (offset_expr.X_op != O_symbol
          && offset_expr.X_op != O_constant)
        {
@@ -6698,8 +6447,6 @@ macro (struct mips_cl_insn *ip)
       if (mips_pic == NO_PIC
          || offset_expr.X_op == O_constant)
        {
-         char *p;
-
          /* If this is a reference to a GP relative symbol, we want
               <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
               <op>     $treg+1,<sym>+4($gp)    (BFD_RELOC_GPREL16)
@@ -6716,34 +6463,25 @@ macro (struct mips_cl_insn *ip)
             the last case.  */
          if ((valueT) offset_expr.X_add_number > MAX_GPREL_OFFSET
              || nopic_need_relax (offset_expr.X_add_symbol, 1))
-           {
-             p = NULL;
-             used_at = 1;
-           }
+           used_at = 1;
          else
            {
-             int off;
-
+             relax_start (offset_expr.X_add_symbol);
              if (breg == 0)
                {
-                 frag_grow (28);
                  tempreg = mips_gp_register;
-                 off = 0;
                  used_at = 0;
                }
              else
                {
-                 frag_grow (36);
-                 macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+                 macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               AT, breg, mips_gp_register);
                  tempreg = AT;
-                 off = 4;
                  used_at = 1;
                }
 
              /* Itbl support may require additional care here.  */
-             macro_build (NULL, &icnt, &offset_expr, s, fmt,
-                          coproc ? treg + 1 : treg,
+             macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
                           BFD_RELOC_GPREL16, tempreg);
              offset_expr.X_add_number += 4;
 
@@ -6752,15 +6490,11 @@ macro (struct mips_cl_insn *ip)
              hold_mips_optimize = mips_optimize;
              mips_optimize = 2;
              /* Itbl support may require additional care here.  */
-             macro_build (NULL, &icnt, &offset_expr, s, fmt,
-                          coproc ? treg : treg + 1,
+             macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
                           BFD_RELOC_GPREL16, tempreg);
              mips_optimize = hold_mips_optimize;
 
-             p = frag_var (rs_machine_dependent, 12 + off, 0,
-                           RELAX_ENCODE (8 + off, 12 + off, 0, 4 + off, 1,
-                                         used_at && mips_opts.noat),
-                           offset_expr.X_add_symbol, 0, NULL);
+             relax_switch ();
 
              /* We just generated two relocs.  When tc_gen_reloc
                 handles this case, it will skip the first reloc and
@@ -6783,33 +6517,22 @@ macro (struct mips_cl_insn *ip)
                  offset_expr.X_op = O_constant;
                }
            }
-         macro_build_lui (p, &icnt, &offset_expr, AT);
-         if (p != NULL)
-           p += 4;
+         macro_build_lui (&offset_expr, AT);
          if (breg != 0)
-           {
-             macro_build (p, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                          AT, breg, AT);
-             if (p != NULL)
-               p += 4;
-           }
+           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
          /* Itbl support may require additional care here.  */
-         macro_build (p, &icnt, &offset_expr, s, fmt,
-                      coproc ? treg + 1 : treg,
+         macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
                       BFD_RELOC_LO16, AT);
-         if (p != NULL)
-           p += 4;
          /* FIXME: How do we handle overflow here?  */
          offset_expr.X_add_number += 4;
          /* Itbl support may require additional care here.  */
-         macro_build (p, &icnt, &offset_expr, s, fmt,
-                      coproc ? treg : treg + 1,
+         macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
                       BFD_RELOC_LO16, AT);
+         if (mips_relax.sequence)
+           relax_end ();
        }
       else if (mips_pic == SVR4_PIC && ! mips_big_got)
        {
-         int off;
-
          /* If this is a reference to an external symbol, we want
               lw       $at,<sym>($gp)          (BFD_RELOC_MIPS_GOT16)
               nop
@@ -6825,43 +6548,39 @@ macro (struct mips_cl_insn *ip)
             in the lwc1 instructions.  */
          used_at = 1;
          expr1.X_add_number = offset_expr.X_add_number;
-         offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000 - 4)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
-         if (breg == 0)
-           off = 0;
-         else
-           off = 4;
-         frag_grow (24 + off);
-         macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
-                      AT, BFD_RELOC_MIPS_GOT16, mips_gp_register);
-         macro_build (NULL, &icnt, NULL, "nop", "");
+         load_got_offset (AT, &offset_expr);
+         load_delay_nop ();
          if (breg != 0)
-           macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                        AT, breg, AT);
-         /* Itbl support may require additional care here.  */
-         macro_build (NULL, &icnt, &expr1, s, fmt, coproc ? treg + 1 : treg,
-                      BFD_RELOC_LO16, AT);
-         expr1.X_add_number += 4;
+           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
 
          /* Set mips_optimize to 2 to avoid inserting an undesired
              nop.  */
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
+
          /* Itbl support may require additional care here.  */
-         macro_build (NULL, &icnt, &expr1, s, fmt, coproc ? treg : treg + 1,
+         relax_start (offset_expr.X_add_symbol);
+         macro_build (&expr1, s, fmt, coproc ? treg + 1 : treg,
                       BFD_RELOC_LO16, AT);
-         mips_optimize = hold_mips_optimize;
+         expr1.X_add_number += 4;
+         macro_build (&expr1, s, fmt, coproc ? treg : treg + 1,
+                      BFD_RELOC_LO16, AT);
+         relax_switch ();
+         macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
+                      BFD_RELOC_LO16, AT);
+         offset_expr.X_add_number += 4;
+         macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
+                      BFD_RELOC_LO16, AT);
+         relax_end ();
 
-         (void) frag_var (rs_machine_dependent, 0, 0,
-                          RELAX_ENCODE (0, 0, -16 - off, -8, 1, 0),
-                          offset_expr.X_add_symbol, 0, NULL);
+         mips_optimize = hold_mips_optimize;
        }
       else if (mips_pic == SVR4_PIC)
        {
-         int gpdel, off;
-         char *p;
+         int gpdelay;
 
          /* If this is a reference to an external symbol, we want
               lui      $at,<sym>               (BFD_RELOC_MIPS_GOT_HI16)
@@ -6884,27 +6603,19 @@ macro (struct mips_cl_insn *ip)
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000 - 4)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
-         if (reg_needs_delay (mips_gp_register))
-           gpdel = 4;
-         else
-           gpdel = 0;
-         if (breg == 0)
-           off = 0;
-         else
-           off = 4;
-         frag_grow (56);
-         macro_build (NULL, &icnt, &offset_expr, "lui", "t,u", AT,
-                      BFD_RELOC_MIPS_GOT_HI16);
-         macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+         gpdelay = reg_needs_delay (mips_gp_register);
+         relax_start (offset_expr.X_add_symbol);
+         macro_build (&offset_expr, "lui", "t,u",
+                      AT, BFD_RELOC_MIPS_GOT_HI16);
+         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                       AT, AT, mips_gp_register);
-         macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                       AT, BFD_RELOC_MIPS_GOT_LO16, AT);
-         macro_build (NULL, &icnt, NULL, "nop", "");
+         load_delay_nop ();
          if (breg != 0)
-           macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                        AT, breg, AT);
+           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
          /* Itbl support may require additional care here.  */
-         macro_build (NULL, &icnt, &expr1, s, fmt, coproc ? treg + 1 : treg,
+         macro_build (&expr1, s, fmt, coproc ? treg + 1 : treg,
                       BFD_RELOC_LO16, AT);
          expr1.X_add_number += 4;
 
@@ -6913,78 +6624,34 @@ macro (struct mips_cl_insn *ip)
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
          /* Itbl support may require additional care here.  */
-         macro_build (NULL, &icnt, &expr1, s, fmt, coproc ? treg : treg + 1,
+         macro_build (&expr1, s, fmt, coproc ? treg : treg + 1,
                       BFD_RELOC_LO16, AT);
          mips_optimize = hold_mips_optimize;
          expr1.X_add_number -= 4;
 
-         p = frag_var (rs_machine_dependent, 16 + gpdel + off, 0,
-                       RELAX_ENCODE (24 + off, 16 + gpdel + off, gpdel,
-                                     8 + gpdel + off, 1, 0),
-                       offset_expr.X_add_symbol, 0, NULL);
-         if (gpdel > 0)
-           {
-             macro_build (p, &icnt, NULL, "nop", "");
-             p += 4;
-           }
-         macro_build (p, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
-                      AT, BFD_RELOC_MIPS_GOT16, mips_gp_register);
-         p += 4;
-         macro_build (p, &icnt, NULL, "nop", "");
-         p += 4;
+         relax_switch ();
+         offset_expr.X_add_number = expr1.X_add_number;
+         if (gpdelay)
+           macro_build (NULL, "nop", "");
+         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
+                      BFD_RELOC_MIPS_GOT16, mips_gp_register);
+         load_delay_nop ();
          if (breg != 0)
-           {
-             macro_build (p, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                          AT, breg, AT);
-             p += 4;
-           }
+           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
          /* Itbl support may require additional care here.  */
-         macro_build (p, &icnt, &expr1, s, fmt, coproc ? treg + 1 : treg,
+         macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
                       BFD_RELOC_LO16, AT);
-         p += 4;
-         expr1.X_add_number += 4;
+         offset_expr.X_add_number += 4;
 
          /* Set mips_optimize to 2 to avoid inserting an undesired
              nop.  */
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
          /* Itbl support may require additional care here.  */
-         macro_build (p, &icnt, &expr1, s, fmt, coproc ? treg : treg + 1,
+         macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
                       BFD_RELOC_LO16, AT);
          mips_optimize = hold_mips_optimize;
-       }
-      else if (mips_pic == EMBEDDED_PIC)
-       {
-         /* If there is no base register, we use
-              <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
-              <op>     $treg+1,<sym>+4($gp)    (BFD_RELOC_GPREL16)
-            If we have a base register, we use
-              addu     $at,$breg,$gp
-              <op>     $treg,<sym>($at)        (BFD_RELOC_GPREL16)
-              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_GPREL16)
-            */
-         if (breg == 0)
-           {
-             tempreg = mips_gp_register;
-             used_at = 0;
-           }
-         else
-           {
-             macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                          AT, breg, mips_gp_register);
-             tempreg = AT;
-             used_at = 1;
-           }
-
-         /* Itbl support may require additional care here.  */
-         macro_build (NULL, &icnt, &offset_expr, s, fmt,
-                      coproc ? treg + 1 : treg,
-                      BFD_RELOC_GPREL16, tempreg);
-         offset_expr.X_add_number += 4;
-         /* Itbl support may require additional care here.  */
-         macro_build (NULL, &icnt, &offset_expr, s, fmt,
-                      coproc ? treg : treg + 1,
-                      BFD_RELOC_GPREL16, tempreg);
+         relax_end ();
        }
       else
        abort ();
@@ -7001,11 +6668,9 @@ macro (struct mips_cl_insn *ip)
       s = "sw";
     sd_ob:
       assert (HAVE_32BIT_ADDRESSES);
-      macro_build (NULL, &icnt, &offset_expr, s, "t,o(b)", treg,
-                  BFD_RELOC_LO16, breg);
+      macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
       offset_expr.X_add_number += 4;
-      macro_build (NULL, &icnt, &offset_expr, s, "t,o(b)", treg + 1,
-                  BFD_RELOC_LO16, breg);
+      macro_build (&offset_expr, s, "t,o(b)", treg + 1, BFD_RELOC_LO16, breg);
       return;
 
    /* New code added to support COPZ instructions.
@@ -7039,11 +6704,11 @@ macro (struct mips_cl_insn *ip)
     copz:
       /* For now we just do C (same as Cz).  The parameter will be
          stored in insn_opcode by mips_ip.  */
-      macro_build (NULL, &icnt, NULL, s, "C", ip->insn_opcode);
+      macro_build (NULL, s, "C", ip->insn_opcode);
       return;
 
     case M_MOVE:
-      move_register (&icnt, dreg, sreg);
+      move_register (dreg, sreg);
       return;
 
 #ifdef LOSING_COMPILER
@@ -7062,7 +6727,7 @@ macro (struct mips_cl_insn *ip)
          s = ip->insn_mo->name;
          s2 = "cop3";
          coproc = ITBL_DECODE_PNUM (immed_expr);;
-         macro_build (NULL, &icnt, &immed_expr, s, "C");
+         macro_build (&immed_expr, s, "C");
          return;
        }
       macro2 (ip);
@@ -7078,7 +6743,6 @@ macro2 (struct mips_cl_insn *ip)
   register int treg, sreg, dreg, breg;
   int tempreg;
   int mask;
-  int icnt = 0;
   int used_at;
   expressionS expr1;
   const char *s;
@@ -7092,7 +6756,6 @@ macro2 (struct mips_cl_insn *ip)
   int off;
   offsetT maxnum;
   bfd_reloc_code_real_type r;
-  char *p;
 
   treg = (ip->insn_opcode >> 16) & 0x1f;
   dreg = (ip->insn_opcode >> 11) & 0x1f;
@@ -7111,9 +6774,8 @@ macro2 (struct mips_cl_insn *ip)
     case M_DMUL:
       dbl = 1;
     case M_MUL:
-      macro_build (NULL, &icnt, NULL, dbl ? "dmultu" : "multu", "s,t",
-                  sreg, treg);
-      macro_build (NULL, &icnt, NULL, "mflo", "d", dreg);
+      macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", sreg, treg);
+      macro_build (NULL, "mflo", "d", dreg);
       return;
 
     case M_DMUL_I:
@@ -7122,10 +6784,9 @@ macro2 (struct mips_cl_insn *ip)
       /* The MIPS assembler some times generates shifts and adds.  I'm
         not trying to be that fancy. GCC should do this for us
         anyway.  */
-      load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build (NULL, &icnt, NULL, dbl ? "dmult" : "mult", "s,t",
-                  sreg, AT);
-      macro_build (NULL, &icnt, NULL, "mflo", "d", dreg);
+      load_register (AT, &imm_expr, dbl);
+      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, AT);
+      macro_build (NULL, "mflo", "d", dreg);
       break;
 
     case M_DMULO_I:
@@ -7142,24 +6803,22 @@ macro2 (struct mips_cl_insn *ip)
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
       if (imm)
-       load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build (NULL, &icnt, NULL, dbl ? "dmult" : "mult", "s,t",
-                  sreg, imm ? AT : treg);
-      macro_build (NULL, &icnt, NULL, "mflo", "d", dreg);
-      macro_build (NULL, &icnt, NULL, dbl ? "dsra32" : "sra", "d,w,<",
-                  dreg, dreg, RA);
-      macro_build (NULL, &icnt, NULL, "mfhi", "d", AT);
+       load_register (AT, &imm_expr, dbl);
+      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, imm ? AT : treg);
+      macro_build (NULL, "mflo", "d", dreg);
+      macro_build (NULL, dbl ? "dsra32" : "sra", "d,w,<", dreg, dreg, RA);
+      macro_build (NULL, "mfhi", "d", AT);
       if (mips_trap)
-       macro_build (NULL, &icnt, NULL, "tne", "s,t,q", dreg, AT, 6);
+       macro_build (NULL, "tne", "s,t,q", dreg, AT, 6);
       else
        {
          expr1.X_add_number = 8;
-         macro_build (NULL, &icnt, &expr1, "beq", "s,t,p", dreg, AT);
-         macro_build (NULL, &icnt, NULL, "nop", "", 0);
-         macro_build (NULL, &icnt, NULL, "break", "c", 6);
+         macro_build (&expr1, "beq", "s,t,p", dreg, AT);
+         macro_build (NULL, "nop", "", 0);
+         macro_build (NULL, "break", "c", 6);
        }
       --mips_opts.noreorder;
-      macro_build (NULL, &icnt, NULL, "mflo", "d", dreg);
+      macro_build (NULL, "mflo", "d", dreg);
       break;
 
     case M_DMULOU_I:
@@ -7176,19 +6835,19 @@ macro2 (struct mips_cl_insn *ip)
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
       if (imm)
-       load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build (NULL, &icnt, NULL, dbl ? "dmultu" : "multu", "s,t",
+       load_register (AT, &imm_expr, dbl);
+      macro_build (NULL, dbl ? "dmultu" : "multu", "s,t",
                   sreg, imm ? AT : treg);
-      macro_build (NULL, &icnt, NULL, "mfhi", "d", AT);
-      macro_build (NULL, &icnt, NULL, "mflo", "d", dreg);
+      macro_build (NULL, "mfhi", "d", AT);
+      macro_build (NULL, "mflo", "d", dreg);
       if (mips_trap)
-       macro_build (NULL, &icnt, NULL, "tne", "s,t,q", AT, 0, 6);
+       macro_build (NULL, "tne", "s,t,q", AT, 0, 6);
       else
        {
          expr1.X_add_number = 8;
-         macro_build (NULL, &icnt, &expr1, "beq", "s,t,p", AT, 0);
-         macro_build (NULL, &icnt, NULL, "nop", "", 0);
-         macro_build (NULL, &icnt, NULL, "break", "c", 6);
+         macro_build (&expr1, "beq", "s,t,p", AT, 0);
+         macro_build (NULL, "nop", "", 0);
+         macro_build (NULL, "break", "c", 6);
        }
       --mips_opts.noreorder;
       break;
@@ -7206,17 +6865,16 @@ macro2 (struct mips_cl_insn *ip)
              tempreg = dreg;
              used_at = 0;
            }
-         macro_build (NULL, &icnt, NULL, "dnegu", "d,w", tempreg, treg);
-         macro_build (NULL, &icnt, NULL, "drorv", "d,t,s", dreg, sreg,
-                      tempreg);
+         macro_build (NULL, "dnegu", "d,w", tempreg, treg);
+         macro_build (NULL, "drorv", "d,t,s", dreg, sreg, tempreg);
          if (used_at)
            break;
          return;
        }
-      macro_build (NULL, &icnt, NULL, "dsubu", "d,v,t", AT, 0, treg);
-      macro_build (NULL, &icnt, NULL, "dsrlv", "d,t,s", AT, sreg, AT);
-      macro_build (NULL, &icnt, NULL, "dsllv", "d,t,s", dreg, sreg, treg);
-      macro_build (NULL, &icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+      macro_build (NULL, "dsubu", "d,v,t", AT, 0, treg);
+      macro_build (NULL, "dsrlv", "d,t,s", AT, sreg, AT);
+      macro_build (NULL, "dsllv", "d,t,s", dreg, sreg, treg);
+      macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
       break;
 
     case M_ROL:
@@ -7232,17 +6890,16 @@ macro2 (struct mips_cl_insn *ip)
              tempreg = dreg;
              used_at = 0;
            }
-         macro_build (NULL, &icnt, NULL, "negu", "d,w", tempreg, treg);
-         macro_build (NULL, &icnt, NULL, "rorv", "d,t,s", dreg, sreg,
-                      tempreg);
+         macro_build (NULL, "negu", "d,w", tempreg, treg);
+         macro_build (NULL, "rorv", "d,t,s", dreg, sreg, tempreg);
          if (used_at)
            break;
          return;
        }
-      macro_build (NULL, &icnt, NULL, "subu", "d,v,t", AT, 0, treg);
-      macro_build (NULL, &icnt, NULL, "srlv", "d,t,s", AT, sreg, AT);
-      macro_build (NULL, &icnt, NULL, "sllv", "d,t,s", dreg, sreg, treg);
-      macro_build (NULL, &icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+      macro_build (NULL, "subu", "d,v,t", AT, 0, treg);
+      macro_build (NULL, "srlv", "d,t,s", AT, sreg, AT);
+      macro_build (NULL, "sllv", "d,t,s", dreg, sreg, treg);
+      macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
       break;
 
     case M_DROL_I:
@@ -7257,25 +6914,22 @@ macro2 (struct mips_cl_insn *ip)
          {
            rot = (64 - rot) & 0x3f;
            if (rot >= 32)
-             macro_build (NULL, &icnt, NULL, "dror32", "d,w,<",
-                          dreg, sreg, rot - 32);
+             macro_build (NULL, "dror32", "d,w,<", dreg, sreg, rot - 32);
            else
-             macro_build (NULL, &icnt, NULL, "dror", "d,w,<",
-                          dreg, sreg, rot);
+             macro_build (NULL, "dror", "d,w,<", dreg, sreg, rot);
            return;
          }
        if (rot == 0)
          {
-           macro_build (NULL, &icnt, NULL, "dsrl", "d,w,<", dreg, sreg, 0);
+           macro_build (NULL, "dsrl", "d,w,<", dreg, sreg, 0);
            return;
          }
        l = (rot < 0x20) ? "dsll" : "dsll32";
        r = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
        rot &= 0x1f;
-       macro_build (NULL, &icnt, NULL, l, "d,w,<", AT, sreg, rot);
-       macro_build (NULL, &icnt, NULL, r, "d,w,<", dreg, sreg,
-                    (0x20 - rot) & 0x1f);
-       macro_build (NULL, &icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+       macro_build (NULL, l, "d,w,<", AT, sreg, rot);
+       macro_build (NULL, r, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
+       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
       }
       break;
 
@@ -7288,44 +6942,42 @@ macro2 (struct mips_cl_insn *ip)
        rot = imm_expr.X_add_number & 0x1f;
        if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
          {
-           macro_build (NULL, &icnt, NULL, "ror", "d,w,<", dreg, sreg,
-                        (32 - rot) & 0x1f);
+           macro_build (NULL, "ror", "d,w,<", dreg, sreg, (32 - rot) & 0x1f);
            return;
          }
        if (rot == 0)
          {
-           macro_build (NULL, &icnt, NULL, "srl", "d,w,<", dreg, sreg, 0);
+           macro_build (NULL, "srl", "d,w,<", dreg, sreg, 0);
            return;
          }
-       macro_build (NULL, &icnt, NULL, "sll", "d,w,<", AT, sreg, rot);
-       macro_build (NULL, &icnt, NULL, "srl", "d,w,<", dreg, sreg,
-                    (0x20 - rot) & 0x1f);
-       macro_build (NULL, &icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+       macro_build (NULL, "sll", "d,w,<", AT, sreg, rot);
+       macro_build (NULL, "srl", "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
+       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
       }
       break;
 
     case M_DROR:
       if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
        {
-         macro_build (NULL, &icnt, NULL, "drorv", "d,t,s", dreg, sreg, treg);
+         macro_build (NULL, "drorv", "d,t,s", dreg, sreg, treg);
          return;
        }
-      macro_build (NULL, &icnt, NULL, "dsubu", "d,v,t", AT, 0, treg);
-      macro_build (NULL, &icnt, NULL, "dsllv", "d,t,s", AT, sreg, AT);
-      macro_build (NULL, &icnt, NULL, "dsrlv", "d,t,s", dreg, sreg, treg);
-      macro_build (NULL, &icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+      macro_build (NULL, "dsubu", "d,v,t", AT, 0, treg);
+      macro_build (NULL, "dsllv", "d,t,s", AT, sreg, AT);
+      macro_build (NULL, "dsrlv", "d,t,s", dreg, sreg, treg);
+      macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
       break;
 
     case M_ROR:
       if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
        {
-         macro_build (NULL, &icnt, NULL, "rorv", "d,t,s", dreg, sreg, treg);
+         macro_build (NULL, "rorv", "d,t,s", dreg, sreg, treg);
          return;
        }
-      macro_build (NULL, &icnt, NULL, "subu", "d,v,t", AT, 0, treg);
-      macro_build (NULL, &icnt, NULL, "sllv", "d,t,s", AT, sreg, AT);
-      macro_build (NULL, &icnt, NULL, "srlv", "d,t,s", dreg, sreg, treg);
-      macro_build (NULL, &icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+      macro_build (NULL, "subu", "d,v,t", AT, 0, treg);
+      macro_build (NULL, "sllv", "d,t,s", AT, sreg, AT);
+      macro_build (NULL, "srlv", "d,t,s", dreg, sreg, treg);
+      macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
       break;
 
     case M_DROR_I:
@@ -7339,25 +6991,22 @@ macro2 (struct mips_cl_insn *ip)
        if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
          {
            if (rot >= 32)
-             macro_build (NULL, &icnt, NULL, "dror32", "d,w,<",
-                          dreg, sreg, rot - 32);
+             macro_build (NULL, "dror32", "d,w,<", dreg, sreg, rot - 32);
            else
-             macro_build (NULL, &icnt, NULL, "dror", "d,w,<",
-                          dreg, sreg, rot);
+             macro_build (NULL, "dror", "d,w,<", dreg, sreg, rot);
            return;
          }
        if (rot == 0)
          {
-           macro_build (NULL, &icnt, NULL, "dsrl", "d,w,<", dreg, sreg, 0);
+           macro_build (NULL, "dsrl", "d,w,<", dreg, sreg, 0);
            return;
          }
        r = (rot < 0x20) ? "dsrl" : "dsrl32";
        l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
        rot &= 0x1f;
-       macro_build (NULL, &icnt, NULL, r, "d,w,<", AT, sreg, rot);
-       macro_build (NULL, &icnt, NULL, l, "d,w,<", dreg, sreg,
-                    (0x20 - rot) & 0x1f);
-       macro_build (NULL, &icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+       macro_build (NULL, r, "d,w,<", AT, sreg, rot);
+       macro_build (NULL, l, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
+       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
       }
       break;
 
@@ -7370,18 +7019,17 @@ macro2 (struct mips_cl_insn *ip)
        rot = imm_expr.X_add_number & 0x1f;
        if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
          {
-           macro_build (NULL, &icnt, NULL, "ror", "d,w,<", dreg, sreg, rot);
+           macro_build (NULL, "ror", "d,w,<", dreg, sreg, rot);
            return;
          }
        if (rot == 0)
          {
-           macro_build (NULL, &icnt, NULL, "srl", "d,w,<", dreg, sreg, 0);
+           macro_build (NULL, "srl", "d,w,<", dreg, sreg, 0);
            return;
          }
-       macro_build (NULL, &icnt, NULL, "srl", "d,w,<", AT, sreg, rot);
-       macro_build (NULL, &icnt, NULL, "sll", "d,w,<", dreg, sreg,
-                    (0x20 - rot) & 0x1f);
-       macro_build (NULL, &icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
+       macro_build (NULL, "srl", "d,w,<", AT, sreg, rot);
+       macro_build (NULL, "sll", "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
+       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
       }
       break;
 
@@ -7394,50 +7042,43 @@ macro2 (struct mips_cl_insn *ip)
       assert (mips_opts.isa == ISA_MIPS1);
       /* Even on a big endian machine $fn comes before $fn+1.  We have
         to adjust when storing to memory.  */
-      macro_build (NULL, &icnt, &offset_expr, "swc1", "T,o(b)",
-                  target_big_endian ? treg + 1 : treg,
-                  BFD_RELOC_LO16, breg);
+      macro_build (&offset_expr, "swc1", "T,o(b)",
+                  target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
       offset_expr.X_add_number += 4;
-      macro_build (NULL, &icnt, &offset_expr, "swc1", "T,o(b)",
-                  target_big_endian ? treg : treg + 1,
-                  BFD_RELOC_LO16, breg);
+      macro_build (&offset_expr, "swc1", "T,o(b)",
+                  target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
       return;
 
     case M_SEQ:
       if (sreg == 0)
-       macro_build (NULL, &icnt, &expr1, "sltiu", "t,r,j", dreg, treg,
-                    BFD_RELOC_LO16);
+       macro_build (&expr1, "sltiu", "t,r,j", dreg, treg, BFD_RELOC_LO16);
       else if (treg == 0)
-       macro_build (NULL, &icnt, &expr1, "sltiu", "t,r,j", dreg, sreg,
-                    BFD_RELOC_LO16);
+       macro_build (&expr1, "sltiu", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
       else
        {
-         macro_build (NULL, &icnt, NULL, "xor", "d,v,t", dreg, sreg, treg);
-         macro_build (NULL, &icnt, &expr1, "sltiu", "t,r,j", dreg, dreg,
-                      BFD_RELOC_LO16);
+         macro_build (NULL, "xor", "d,v,t", dreg, sreg, treg);
+         macro_build (&expr1, "sltiu", "t,r,j", dreg, dreg, BFD_RELOC_LO16);
        }
       return;
 
     case M_SEQ_I:
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
-         macro_build (NULL, &icnt, &expr1, "sltiu", "t,r,j", dreg, sreg,
-                      BFD_RELOC_LO16);
+         macro_build (&expr1, "sltiu", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
          return;
        }
       if (sreg == 0)
        {
          as_warn (_("Instruction %s: result is always false"),
                   ip->insn_mo->name);
-         move_register (&icnt, dreg, 0);
+         move_register (dreg, 0);
          return;
        }
       if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number >= 0
          && imm_expr.X_add_number < 0x10000)
        {
-         macro_build (NULL, &icnt, &imm_expr, "xori", "t,r,i", dreg, sreg,
-                      BFD_RELOC_LO16);
+         macro_build (&imm_expr, "xori", "t,r,i", dreg, sreg, BFD_RELOC_LO16);
          used_at = 0;
        }
       else if (imm_expr.X_op == O_constant
@@ -7445,19 +7086,17 @@ macro2 (struct mips_cl_insn *ip)
               && imm_expr.X_add_number < 0)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
-         macro_build (NULL, &icnt, &imm_expr,
-                      HAVE_32BIT_GPRS ? "addiu" : "daddiu",
+         macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
                       "t,r,j", dreg, sreg, BFD_RELOC_LO16);
          used_at = 0;
        }
       else
        {
-         load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
-         macro_build (NULL, &icnt, NULL, "xor", "d,v,t", dreg, sreg, AT);
+         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+         macro_build (NULL, "xor", "d,v,t", dreg, sreg, AT);
          used_at = 1;
        }
-      macro_build (NULL, &icnt, &expr1, "sltiu", "t,r,j", dreg, dreg,
-                  BFD_RELOC_LO16);
+      macro_build (&expr1, "sltiu", "t,r,j", dreg, dreg, BFD_RELOC_LO16);
       if (used_at)
        break;
       return;
@@ -7468,9 +7107,8 @@ macro2 (struct mips_cl_insn *ip)
     case M_SGEU:
       s = "sltu";
     sge:
-      macro_build (NULL, &icnt, NULL, s, "d,v,t", dreg, sreg, treg);
-      macro_build (NULL, &icnt, &expr1, "xori", "t,r,i", dreg, dreg,
-                  BFD_RELOC_LO16);
+      macro_build (NULL, s, "d,v,t", dreg, sreg, treg);
+      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
       return;
 
     case M_SGE_I:              /* sreg >= I <==> not (sreg < I) */
@@ -7479,20 +7117,18 @@ macro2 (struct mips_cl_insn *ip)
          && imm_expr.X_add_number >= -0x8000
          && imm_expr.X_add_number < 0x8000)
        {
-         macro_build (NULL, &icnt, &imm_expr,
-                      mask == M_SGE_I ? "slti" : "sltiu",
-                      "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+         macro_build (&imm_expr, mask == M_SGE_I ? "slti" : "sltiu", "t,r,j",
+                      dreg, sreg, BFD_RELOC_LO16);
          used_at = 0;
        }
       else
        {
-         load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
-         macro_build (NULL, &icnt, NULL, mask == M_SGE_I ? "slt" : "sltu",
-                      "d,v,t", dreg, sreg, AT);
+         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+         macro_build (NULL, mask == M_SGE_I ? "slt" : "sltu", "d,v,t",
+                      dreg, sreg, AT);
          used_at = 1;
        }
-      macro_build (NULL, &icnt, &expr1, "xori", "t,r,i", dreg, dreg,
-                  BFD_RELOC_LO16);
+      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
       if (used_at)
        break;
       return;
@@ -7503,7 +7139,7 @@ macro2 (struct mips_cl_insn *ip)
     case M_SGTU:
       s = "sltu";
     sgt:
-      macro_build (NULL, &icnt, NULL, s, "d,v,t", dreg, treg, sreg);
+      macro_build (NULL, s, "d,v,t", dreg, treg, sreg);
       return;
 
     case M_SGT_I:              /* sreg > I  <==>  I < sreg */
@@ -7512,8 +7148,8 @@ macro2 (struct mips_cl_insn *ip)
     case M_SGTU_I:
       s = "sltu";
     sgti:
-      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, &icnt, NULL, s, "d,v,t", dreg, AT, sreg);
+      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      macro_build (NULL, s, "d,v,t", dreg, AT, sreg);
       break;
 
     case M_SLE:        /* sreg <= treg  <==>  treg >= sreg  <==>  not (treg < sreg) */
@@ -7522,9 +7158,8 @@ macro2 (struct mips_cl_insn *ip)
     case M_SLEU:
       s = "sltu";
     sle:
-      macro_build (NULL, &icnt, NULL, s, "d,v,t", dreg, treg, sreg);
-      macro_build (NULL, &icnt, &expr1, "xori", "t,r,i", dreg, dreg,
-                  BFD_RELOC_LO16);
+      macro_build (NULL, s, "d,v,t", dreg, treg, sreg);
+      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
       return;
 
     case M_SLE_I:      /* sreg <= I <==> I >= sreg <==> not (I < sreg) */
@@ -7533,10 +7168,9 @@ macro2 (struct mips_cl_insn *ip)
     case M_SLEU_I:
       s = "sltu";
     slei:
-      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, &icnt, NULL, s, "d,v,t", dreg, AT, sreg);
-      macro_build (NULL, &icnt, &expr1, "xori", "t,r,i", dreg, dreg,
-                  BFD_RELOC_LO16);
+      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      macro_build (NULL, s, "d,v,t", dreg, AT, sreg);
+      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
       break;
 
     case M_SLT_I:
@@ -7544,12 +7178,11 @@ macro2 (struct mips_cl_insn *ip)
          && imm_expr.X_add_number >= -0x8000
          && imm_expr.X_add_number < 0x8000)
        {
-         macro_build (NULL, &icnt, &imm_expr, "slti", "t,r,j", dreg, sreg,
-                      BFD_RELOC_LO16);
+         macro_build (&imm_expr, "slti", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
          return;
        }
-      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, &icnt, NULL, "slt", "d,v,t", dreg, sreg, AT);
+      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      macro_build (NULL, "slt", "d,v,t", dreg, sreg, AT);
       break;
 
     case M_SLTU_I:
@@ -7557,47 +7190,45 @@ macro2 (struct mips_cl_insn *ip)
          && imm_expr.X_add_number >= -0x8000
          && imm_expr.X_add_number < 0x8000)
        {
-         macro_build (NULL, &icnt, &imm_expr, "sltiu", "t,r,j", dreg, sreg,
+         macro_build (&imm_expr, "sltiu", "t,r,j", dreg, sreg,
                       BFD_RELOC_LO16);
          return;
        }
-      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, &icnt, NULL, "sltu", "d,v,t", dreg, sreg, AT);
+      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      macro_build (NULL, "sltu", "d,v,t", dreg, sreg, AT);
       break;
 
     case M_SNE:
       if (sreg == 0)
-       macro_build (NULL, &icnt, NULL, "sltu","d,v,t", dreg, 0, treg);
+       macro_build (NULL, "sltu", "d,v,t", dreg, 0, treg);
       else if (treg == 0)
-       macro_build (NULL, &icnt, NULL, "sltu", "d,v,t", dreg, 0, sreg);
+       macro_build (NULL, "sltu", "d,v,t", dreg, 0, sreg);
       else
        {
-         macro_build (NULL, &icnt, NULL, "xor", "d,v,t", dreg, sreg, treg);
-         macro_build (NULL, &icnt, NULL, "sltu", "d,v,t", dreg, 0, dreg);
+         macro_build (NULL, "xor", "d,v,t", dreg, sreg, treg);
+         macro_build (NULL, "sltu", "d,v,t", dreg, 0, dreg);
        }
       return;
 
     case M_SNE_I:
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
-         macro_build (NULL, &icnt, NULL, "sltu", "d,v,t", dreg, 0, sreg);
+         macro_build (NULL, "sltu", "d,v,t", dreg, 0, sreg);
          return;
        }
       if (sreg == 0)
        {
          as_warn (_("Instruction %s: result is always true"),
                   ip->insn_mo->name);
-         macro_build (NULL, &icnt, &expr1,
-                      HAVE_32BIT_GPRS ? "addiu" : "daddiu",
-                      "t,r,j", dreg, 0, BFD_RELOC_LO16);
+         macro_build (&expr1, HAVE_32BIT_GPRS ? "addiu" : "daddiu", "t,r,j",
+                      dreg, 0, BFD_RELOC_LO16);
          return;
        }
       if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number >= 0
          && imm_expr.X_add_number < 0x10000)
        {
-         macro_build (NULL, &icnt, &imm_expr, "xori", "t,r,i", dreg, sreg,
-                      BFD_RELOC_LO16);
+         macro_build (&imm_expr, "xori", "t,r,i", dreg, sreg, BFD_RELOC_LO16);
          used_at = 0;
        }
       else if (imm_expr.X_op == O_constant
@@ -7605,18 +7236,17 @@ macro2 (struct mips_cl_insn *ip)
               && imm_expr.X_add_number < 0)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
-         macro_build (NULL, &icnt, &imm_expr,
-                      HAVE_32BIT_GPRS ? "addiu" : "daddiu",
+         macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
                       "t,r,j", dreg, sreg, BFD_RELOC_LO16);
          used_at = 0;
        }
       else
        {
-         load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
-         macro_build (NULL, &icnt, NULL, "xor", "d,v,t", dreg, sreg, AT);
+         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+         macro_build (NULL, "xor", "d,v,t", dreg, sreg, AT);
          used_at = 1;
        }
-      macro_build (NULL, &icnt, NULL, "sltu", "d,v,t", dreg, 0, dreg);
+      macro_build (NULL, "sltu", "d,v,t", dreg, 0, dreg);
       if (used_at)
        break;
       return;
@@ -7629,13 +7259,12 @@ macro2 (struct mips_cl_insn *ip)
          && imm_expr.X_add_number <= 0x8000)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
-         macro_build (NULL, &icnt, &imm_expr, dbl ? "daddi" : "addi",
-                      "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+         macro_build (&imm_expr, dbl ? "daddi" : "addi", "t,r,j",
+                      dreg, sreg, BFD_RELOC_LO16);
          return;
        }
-      load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build (NULL, &icnt, NULL, dbl ? "dsub" : "sub", "d,v,t",
-                  dreg, sreg, AT);
+      load_register (AT, &imm_expr, dbl);
+      macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, sreg, AT);
       break;
 
     case M_DSUBU_I:
@@ -7646,13 +7275,12 @@ macro2 (struct mips_cl_insn *ip)
          && imm_expr.X_add_number <= 0x8000)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
-         macro_build (NULL, &icnt, &imm_expr, dbl ? "daddiu" : "addiu",
-                      "t,r,j", dreg, sreg, BFD_RELOC_LO16);
+         macro_build (&imm_expr, dbl ? "daddiu" : "addiu", "t,r,j",
+                      dreg, sreg, BFD_RELOC_LO16);
          return;
        }
-      load_register (&icnt, AT, &imm_expr, dbl);
-      macro_build (NULL, &icnt, NULL, dbl ? "dsubu" : "subu", "d,v,t",
-                  dreg, sreg, AT);
+      load_register (AT, &imm_expr, dbl);
+      macro_build (NULL, dbl ? "dsubu" : "subu", "d,v,t", dreg, sreg, AT);
       break;
 
     case M_TEQ_I:
@@ -7673,8 +7301,8 @@ macro2 (struct mips_cl_insn *ip)
     case M_TNE_I:
       s = "tne";
     trap:
-      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
-      macro_build (NULL, &icnt, NULL, s, "s,t", sreg, AT);
+      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      macro_build (NULL, s, "s,t", sreg, AT);
       break;
 
     case M_TRUNCWS:
@@ -7690,22 +7318,19 @@ macro2 (struct mips_cl_insn *ip)
       mips_emit_delays (TRUE);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
-      macro_build (NULL, &icnt, NULL, "cfc1", "t,G", treg, RA);
-      macro_build (NULL, &icnt, NULL, "cfc1", "t,G", treg, RA);
-      macro_build (NULL, &icnt, NULL, "nop", "");
+      macro_build (NULL, "cfc1", "t,G", treg, RA);
+      macro_build (NULL, "cfc1", "t,G", treg, RA);
+      macro_build (NULL, "nop", "");
       expr1.X_add_number = 3;
-      macro_build (NULL, &icnt, &expr1, "ori", "t,r,i", AT, treg,
-                  BFD_RELOC_LO16);
+      macro_build (&expr1, "ori", "t,r,i", AT, treg, BFD_RELOC_LO16);
       expr1.X_add_number = 2;
-      macro_build (NULL, &icnt, &expr1, "xori", "t,r,i", AT, AT,
-                  BFD_RELOC_LO16);
-      macro_build (NULL, &icnt, NULL, "ctc1", "t,G", AT, RA);
-      macro_build (NULL, &icnt, NULL, "nop", "");
-      macro_build (NULL, &icnt, NULL,
-                  mask == M_TRUNCWD ? "cvt.w.d" : "cvt.w.s",
-                  "D,S", dreg, sreg);
-      macro_build (NULL, &icnt, NULL, "ctc1", "t,G", treg, RA);
-      macro_build (NULL, &icnt, NULL, "nop", "");
+      macro_build (&expr1, "xori", "t,r,i", AT, AT, BFD_RELOC_LO16);
+      macro_build (NULL, "ctc1", "t,G", AT, RA);
+      macro_build (NULL, "nop", "");
+      macro_build (NULL, mask == M_TRUNCWD ? "cvt.w.d" : "cvt.w.s", "D,S",
+                  dreg, sreg);
+      macro_build (NULL, "ctc1", "t,G", treg, RA);
+      macro_build (NULL, "nop", "");
       --mips_opts.noreorder;
       break;
 
@@ -7719,16 +7344,14 @@ macro2 (struct mips_cl_insn *ip)
        as_bad (_("operand overflow"));
       if (! target_big_endian)
        ++offset_expr.X_add_number;
-      macro_build (NULL, &icnt, &offset_expr, s, "t,o(b)", AT,
-                  BFD_RELOC_LO16, breg);
+      macro_build (&offset_expr, s, "t,o(b)", AT, BFD_RELOC_LO16, breg);
       if (! target_big_endian)
        --offset_expr.X_add_number;
       else
        ++offset_expr.X_add_number;
-      macro_build (NULL, &icnt, &offset_expr, "lbu", "t,o(b)", treg,
-                  BFD_RELOC_LO16, breg);
-      macro_build (NULL, &icnt, NULL, "sll", "d,w,<", AT, AT, 8);
-      macro_build (NULL, &icnt, NULL, "or", "d,v,t", treg, treg, AT);
+      macro_build (&offset_expr, "lbu", "t,o(b)", treg, BFD_RELOC_LO16, breg);
+      macro_build (NULL, "sll", "d,w,<", AT, AT, 8);
+      macro_build (NULL, "or", "d,v,t", treg, treg, AT);
       break;
 
     case M_ULD:
@@ -7749,22 +7372,19 @@ macro2 (struct mips_cl_insn *ip)
        tempreg = AT;
       if (! target_big_endian)
        offset_expr.X_add_number += off;
-      macro_build (NULL, &icnt, &offset_expr, s, "t,o(b)", tempreg,
-                  BFD_RELOC_LO16, breg);
+      macro_build (&offset_expr, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
       if (! target_big_endian)
        offset_expr.X_add_number -= off;
       else
        offset_expr.X_add_number += off;
-      macro_build (NULL, &icnt, &offset_expr, s2, "t,o(b)", tempreg,
-                  BFD_RELOC_LO16, breg);
+      macro_build (&offset_expr, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
 
       /* If necessary, move the result in tempreg the final destination.  */
       if (treg == tempreg)
         return;
       /* Protect second load's delay slot.  */
-      if (!gpr_interlocks)
-       macro_build (NULL, &icnt, NULL, "nop", "");
-      move_register (&icnt, treg, tempreg);
+      load_delay_nop ();
+      move_register (treg, tempreg);
       break;
 
     case M_ULD_A:
@@ -7778,44 +7398,38 @@ macro2 (struct mips_cl_insn *ip)
       off = 3;
     ulwa:
       used_at = 1;
-      load_address (&icnt, AT, &offset_expr, &used_at);
+      load_address (AT, &offset_expr, &used_at);
       if (breg != 0)
-       macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                    AT, AT, breg);
+       macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
       if (! target_big_endian)
        expr1.X_add_number = off;
       else
        expr1.X_add_number = 0;
-      macro_build (NULL, &icnt, &expr1, s, "t,o(b)", treg,
-                  BFD_RELOC_LO16, AT);
+      macro_build (&expr1, s, "t,o(b)", treg, BFD_RELOC_LO16, AT);
       if (! target_big_endian)
        expr1.X_add_number = 0;
       else
        expr1.X_add_number = off;
-      macro_build (NULL, &icnt, &expr1, s2, "t,o(b)", treg,
-                  BFD_RELOC_LO16, AT);
+      macro_build (&expr1, s2, "t,o(b)", treg, BFD_RELOC_LO16, AT);
       break;
 
     case M_ULH_A:
     case M_ULHU_A:
       used_at = 1;
-      load_address (&icnt, AT, &offset_expr, &used_at);
+      load_address (AT, &offset_expr, &used_at);
       if (breg != 0)
-       macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                    AT, AT, breg);
+       macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
       if (target_big_endian)
        expr1.X_add_number = 0;
-      macro_build (NULL, &icnt, &expr1,
-                  mask == M_ULH_A ? "lb" : "lbu", "t,o(b)",
+      macro_build (&expr1, mask == M_ULH_A ? "lb" : "lbu", "t,o(b)",
                   treg, BFD_RELOC_LO16, AT);
       if (target_big_endian)
        expr1.X_add_number = 1;
       else
        expr1.X_add_number = 0;
-      macro_build (NULL, &icnt, &expr1, "lbu", "t,o(b)",
-                  AT, BFD_RELOC_LO16, AT);
-      macro_build (NULL, &icnt, NULL, "sll", "d,w,<", treg, treg, 8);
-      macro_build (NULL, &icnt, NULL, "or", "d,v,t", treg, treg, AT);
+      macro_build (&expr1, "lbu", "t,o(b)", AT, BFD_RELOC_LO16, AT);
+      macro_build (NULL, "sll", "d,w,<", treg, treg, 8);
+      macro_build (NULL, "or", "d,v,t", treg, treg, AT);
       break;
 
     case M_USH:
@@ -7823,15 +7437,13 @@ macro2 (struct mips_cl_insn *ip)
        as_bad (_("operand overflow"));
       if (target_big_endian)
        ++offset_expr.X_add_number;
-      macro_build (NULL, &icnt, &offset_expr, "sb", "t,o(b)", treg,
-                  BFD_RELOC_LO16, breg);
-      macro_build (NULL, &icnt, NULL, "srl", "d,w,<", AT, treg, 8);
+      macro_build (&offset_expr, "sb", "t,o(b)", treg, BFD_RELOC_LO16, breg);
+      macro_build (NULL, "srl", "d,w,<", AT, treg, 8);
       if (target_big_endian)
        --offset_expr.X_add_number;
       else
        ++offset_expr.X_add_number;
-      macro_build (NULL, &icnt, &offset_expr, "sb", "t,o(b)", AT,
-                  BFD_RELOC_LO16, breg);
+      macro_build (&offset_expr, "sb", "t,o(b)", AT, BFD_RELOC_LO16, breg);
       break;
 
     case M_USD:
@@ -7848,14 +7460,12 @@ macro2 (struct mips_cl_insn *ip)
        as_bad (_("operand overflow"));
       if (! target_big_endian)
        offset_expr.X_add_number += off;
-      macro_build (NULL, &icnt, &offset_expr, s, "t,o(b)", treg,
-                  BFD_RELOC_LO16, breg);
+      macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
       if (! target_big_endian)
        offset_expr.X_add_number -= off;
       else
        offset_expr.X_add_number += off;
-      macro_build (NULL, &icnt, &offset_expr, s2, "t,o(b)", treg,
-                  BFD_RELOC_LO16, breg);
+      macro_build (&offset_expr, s2, "t,o(b)", treg, BFD_RELOC_LO16, breg);
       return;
 
     case M_USD_A:
@@ -7869,49 +7479,42 @@ macro2 (struct mips_cl_insn *ip)
       off = 3;
     uswa:
       used_at = 1;
-      load_address (&icnt, AT, &offset_expr, &used_at);
+      load_address (AT, &offset_expr, &used_at);
       if (breg != 0)
-       macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                    AT, AT, breg);
+       macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
       if (! target_big_endian)
        expr1.X_add_number = off;
       else
        expr1.X_add_number = 0;
-      macro_build (NULL, &icnt, &expr1, s, "t,o(b)", treg,
-                  BFD_RELOC_LO16, AT);
+      macro_build (&expr1, s, "t,o(b)", treg, BFD_RELOC_LO16, AT);
       if (! target_big_endian)
        expr1.X_add_number = 0;
       else
        expr1.X_add_number = off;
-      macro_build (NULL, &icnt, &expr1, s2, "t,o(b)", treg,
-                  BFD_RELOC_LO16, AT);
+      macro_build (&expr1, s2, "t,o(b)", treg, BFD_RELOC_LO16, AT);
       break;
 
     case M_USH_A:
       used_at = 1;
-      load_address (&icnt, AT, &offset_expr, &used_at);
+      load_address (AT, &offset_expr, &used_at);
       if (breg != 0)
-       macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-                    AT, AT, breg);
+       macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
       if (! target_big_endian)
        expr1.X_add_number = 0;
-      macro_build (NULL, &icnt, &expr1, "sb", "t,o(b)", treg,
-                  BFD_RELOC_LO16, AT);
-      macro_build (NULL, &icnt, NULL, "srl", "d,w,<", treg, treg, 8);
+      macro_build (&expr1, "sb", "t,o(b)", treg, BFD_RELOC_LO16, AT);
+      macro_build (NULL, "srl", "d,w,<", treg, treg, 8);
       if (! target_big_endian)
        expr1.X_add_number = 1;
       else
        expr1.X_add_number = 0;
-      macro_build (NULL, &icnt, &expr1, "sb", "t,o(b)", treg,
-                  BFD_RELOC_LO16, AT);
+      macro_build (&expr1, "sb", "t,o(b)", treg, BFD_RELOC_LO16, AT);
       if (! target_big_endian)
        expr1.X_add_number = 0;
       else
        expr1.X_add_number = 1;
-      macro_build (NULL, &icnt, &expr1, "lbu", "t,o(b)", AT,
-                  BFD_RELOC_LO16, AT);
-      macro_build (NULL, &icnt, NULL, "sll", "d,w,<", treg, treg, 8);
-      macro_build (NULL, &icnt, NULL, "or", "d,v,t", treg, treg, AT);
+      macro_build (&expr1, "lbu", "t,o(b)", AT, BFD_RELOC_LO16, AT);
+      macro_build (NULL, "sll", "d,w,<", treg, treg, 8);
+      macro_build (NULL, "or", "d,v,t", treg, treg, AT);
       break;
 
     default:
@@ -7931,7 +7534,6 @@ mips16_macro (struct mips_cl_insn *ip)
 {
   int mask;
   int xreg, yreg, zreg, tmp;
-  int icnt;
   expressionS expr1;
   int dbl;
   const char *s, *s2, *s3;
@@ -7942,8 +7544,6 @@ mips16_macro (struct mips_cl_insn *ip)
   yreg = (ip->insn_opcode >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY;
   zreg = (ip->insn_opcode >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
 
-  icnt = 0;
-
   expr1.X_op = O_constant;
   expr1.X_op_symbol = NULL;
   expr1.X_add_symbol = NULL;
@@ -7969,18 +7569,17 @@ mips16_macro (struct mips_cl_insn *ip)
       mips_emit_delays (TRUE);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
-      macro_build (NULL, &icnt, NULL, dbl ? "ddiv" : "div", "0,x,y",
-                  xreg, yreg);
+      macro_build (NULL, dbl ? "ddiv" : "div", "0,x,y", xreg, yreg);
       expr1.X_add_number = 2;
-      macro_build (NULL, &icnt, &expr1, "bnez", "x,p", yreg);
-      macro_build (NULL, &icnt, NULL, "break", "6", 7);
+      macro_build (&expr1, "bnez", "x,p", yreg);
+      macro_build (NULL, "break", "6", 7);
 
       /* FIXME: The normal code checks for of -1 / -0x80000000 here,
          since that causes an overflow.  We should do that as well,
          but I don't see how to do the comparisons without a temporary
          register.  */
       --mips_opts.noreorder;
-      macro_build (NULL, &icnt, NULL, s, "x", zreg);
+      macro_build (NULL, s, "x", zreg);
       break;
 
     case M_DIVU_3:
@@ -8002,20 +7601,19 @@ mips16_macro (struct mips_cl_insn *ip)
       mips_emit_delays (TRUE);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
-      macro_build (NULL, &icnt, NULL, s, "0,x,y", xreg, yreg);
+      macro_build (NULL, s, "0,x,y", xreg, yreg);
       expr1.X_add_number = 2;
-      macro_build (NULL, &icnt, &expr1, "bnez", "x,p", yreg);
-      macro_build (NULL, &icnt, NULL, "break", "6", 7);
+      macro_build (&expr1, "bnez", "x,p", yreg);
+      macro_build (NULL, "break", "6", 7);
       --mips_opts.noreorder;
-      macro_build (NULL, &icnt, NULL, s2, "x", zreg);
+      macro_build (NULL, s2, "x", zreg);
       break;
 
     case M_DMUL:
       dbl = 1;
     case M_MUL:
-      macro_build (NULL, &icnt, NULL, dbl ? "dmultu" : "multu", "x,y",
-                  xreg, yreg);
-      macro_build (NULL, &icnt, NULL, "mflo", "x", zreg);
+      macro_build (NULL, dbl ? "dmultu" : "multu", "x,y", xreg, yreg);
+      macro_build (NULL, "mflo", "x", zreg);
       return;
 
     case M_DSUBU_I:
@@ -8026,22 +7624,21 @@ mips16_macro (struct mips_cl_insn *ip)
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number = -imm_expr.X_add_number;
-      macro_build (NULL, &icnt, &imm_expr, dbl ? "daddiu" : "addiu", "y,x,4",
-                  yreg, xreg);
+      macro_build (&imm_expr, dbl ? "daddiu" : "addiu", "y,x,4", yreg, xreg);
       break;
 
     case M_SUBU_I_2:
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number = -imm_expr.X_add_number;
-      macro_build (NULL, &icnt, &imm_expr, "addiu", "x,k", xreg);
+      macro_build (&imm_expr, "addiu", "x,k", xreg);
       break;
 
     case M_DSUBU_I_2:
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number = -imm_expr.X_add_number;
-      macro_build (NULL, &icnt, &imm_expr, "daddiu", "y,j", yreg);
+      macro_build (&imm_expr, "daddiu", "y,j", yreg);
       break;
 
     case M_BEQ:
@@ -8090,8 +7687,8 @@ mips16_macro (struct mips_cl_insn *ip)
       yreg = tmp;
 
     do_branch:
-      macro_build (NULL, &icnt, NULL, s, "x,y", xreg, yreg);
-      macro_build (NULL, &icnt, &offset_expr, s2, "p");
+      macro_build (NULL, s, "x,y", xreg, yreg);
+      macro_build (&offset_expr, s2, "p");
       break;
 
     case M_BEQ_I:
@@ -8150,18 +7747,18 @@ mips16_macro (struct mips_cl_insn *ip)
       ++imm_expr.X_add_number;
 
     do_branch_i:
-      macro_build (NULL, &icnt, &imm_expr, s, s3, xreg);
-      macro_build (NULL, &icnt, &offset_expr, s2, "p");
+      macro_build (&imm_expr, s, s3, xreg);
+      macro_build (&offset_expr, s2, "p");
       break;
 
     case M_ABS:
       expr1.X_add_number = 0;
-      macro_build (NULL, &icnt, &expr1, "slti", "x,8", yreg);
+      macro_build (&expr1, "slti", "x,8", yreg);
       if (xreg != yreg)
-       move_register (&icnt, xreg, yreg);
+       move_register (xreg, yreg);
       expr1.X_add_number = 2;
-      macro_build (NULL, &icnt, &expr1, "bteqz", "p");
-      macro_build (NULL, &icnt, NULL, "neg", "x,w", xreg, xreg);
+      macro_build (&expr1, "bteqz", "p");
+      macro_build (NULL, "neg", "x,w", xreg, xreg);
     }
 }
 
@@ -9005,6 +8602,7 @@ do_msbd:
                          ip->insn_opcode |= (imm_expr.X_add_number
                                              << (OP_SH_VSEL +
                                                  (is_qh ? 2 : 1)));
+                         imm_expr.X_op = O_absent;
                          if (*s != ']')
                            as_warn(_("Expecting ']' found '%s'"), s);
                          else
@@ -9094,13 +8692,6 @@ do_msbd:
                    The .lit4 and .lit8 sections are only used if
                    permitted by the -G argument.
 
-                   When generating embedded PIC code, we use the
-                   .lit8 section but not the .lit4 section (we can do
-                   .lit4 inline easily; we need to put .lit8
-                   somewhere in the data segment, and using .lit8
-                   permits the linker to eventually combine identical
-                   .lit8 entries).
-
                    The code below needs to know whether the target register
                    is 32 or 64 bits wide.  It relies on the fact 'f' and
                    'F' are used with GPR-based instructions and 'l' and
@@ -9126,9 +8717,7 @@ do_msbd:
 
                if (*args == 'f'
                    || (*args == 'l'
-                       && (! USE_GLOBAL_POINTER_OPT
-                           || mips_pic == EMBEDDED_PIC
-                           || g_switch_value < 4
+                       && (g_switch_value < 4
                            || (temp[0] == 0 && temp[1] == 0)
                            || (temp[2] == 0 && temp[3] == 0))))
                  {
@@ -9215,19 +8804,14 @@ do_msbd:
                      default: /* unused default case avoids warnings.  */
                      case 'L':
                        newname = RDATA_SECTION_NAME;
-                       if ((USE_GLOBAL_POINTER_OPT && g_switch_value >= 8)
-                           || mips_pic == EMBEDDED_PIC)
+                       if (g_switch_value >= 8)
                          newname = ".lit8";
                        break;
                      case 'F':
-                       if (mips_pic == EMBEDDED_PIC)
-                         newname = ".lit8";
-                       else
-                         newname = RDATA_SECTION_NAME;
+                       newname = RDATA_SECTION_NAME;
                        break;
                      case 'l':
-                       assert (!USE_GLOBAL_POINTER_OPT
-                               || g_switch_value >= 4);
+                       assert (g_switch_value >= 4);
                        newname = ".lit4";
                        break;
                      }
@@ -10232,7 +9816,7 @@ parse_relocation (char **str, bfd_reloc_code_real_type *reloc)
          {
            as_bad ("relocation %s isn't supported by the current ABI",
                    percent_op[i].str);
-           *reloc = BFD_RELOC_LO16;
+           *reloc = BFD_RELOC_UNUSED;
          }
        return TRUE;
       }
@@ -10244,8 +9828,7 @@ parse_relocation (char **str, bfd_reloc_code_real_type *reloc)
    expression in *EP and the relocations in the array starting
    at RELOC.  Return the number of relocation operators used.
 
-   On exit, EXPR_END points to the first character after the expression.
-   If no relocation operators are used, RELOC[0] is set to BFD_RELOC_LO16.  */
+   On exit, EXPR_END points to the first character after the expression.  */
 
 static size_t
 my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
@@ -10291,9 +9874,7 @@ my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
 
   expr_end = str;
 
-  if (reloc_index == 0)
-    reloc[0] = BFD_RELOC_LO16;
-  else
+  if (reloc_index != 0)
     {
       prev_reloc_op_frag = frag_now;
       for (i = 0; i < reloc_index; i++)
@@ -10486,45 +10067,43 @@ struct option md_longopts[] =
 #define OPTION_MNO_7000_HILO_FIX (OPTION_FIX_BASE + 1)
   {"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
   {"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
-#define OPTION_FIX_VR4122 (OPTION_FIX_BASE + 2)
-#define OPTION_NO_FIX_VR4122 (OPTION_FIX_BASE + 3)
-  {"mfix-vr4122-bugs",    no_argument, NULL, OPTION_FIX_VR4122},
-  {"no-mfix-vr4122-bugs", no_argument, NULL, OPTION_NO_FIX_VR4122},
+#define OPTION_FIX_VR4120 (OPTION_FIX_BASE + 2)
+#define OPTION_NO_FIX_VR4120 (OPTION_FIX_BASE + 3)
+  {"mfix-vr4120",    no_argument, NULL, OPTION_FIX_VR4120},
+  {"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
 
   /* Miscellaneous options.  */
 #define OPTION_MISC_BASE (OPTION_FIX_BASE + 4)
-#define OPTION_MEMBEDDED_PIC (OPTION_MISC_BASE + 0)
-  {"membedded-pic", no_argument, NULL, OPTION_MEMBEDDED_PIC},
-#define OPTION_TRAP (OPTION_MISC_BASE + 1)
+#define OPTION_TRAP (OPTION_MISC_BASE + 0)
   {"trap", no_argument, NULL, OPTION_TRAP},
   {"no-break", no_argument, NULL, OPTION_TRAP},
-#define OPTION_BREAK (OPTION_MISC_BASE + 2)
+#define OPTION_BREAK (OPTION_MISC_BASE + 1)
   {"break", no_argument, NULL, OPTION_BREAK},
   {"no-trap", no_argument, NULL, OPTION_BREAK},
-#define OPTION_EB (OPTION_MISC_BASE + 3)
+#define OPTION_EB (OPTION_MISC_BASE + 2)
   {"EB", no_argument, NULL, OPTION_EB},
-#define OPTION_EL (OPTION_MISC_BASE + 4)
+#define OPTION_EL (OPTION_MISC_BASE + 3)
   {"EL", no_argument, NULL, OPTION_EL},
-#define OPTION_FP32 (OPTION_MISC_BASE + 5)
+#define OPTION_FP32 (OPTION_MISC_BASE + 4)
   {"mfp32", no_argument, NULL, OPTION_FP32},
-#define OPTION_GP32 (OPTION_MISC_BASE + 6)
+#define OPTION_GP32 (OPTION_MISC_BASE + 5)
   {"mgp32", no_argument, NULL, OPTION_GP32},
-#define OPTION_CONSTRUCT_FLOATS (OPTION_MISC_BASE + 7)
+#define OPTION_CONSTRUCT_FLOATS (OPTION_MISC_BASE + 6)
   {"construct-floats", no_argument, NULL, OPTION_CONSTRUCT_FLOATS},
-#define OPTION_NO_CONSTRUCT_FLOATS (OPTION_MISC_BASE + 8)
+#define OPTION_NO_CONSTRUCT_FLOATS (OPTION_MISC_BASE + 7)
   {"no-construct-floats", no_argument, NULL, OPTION_NO_CONSTRUCT_FLOATS},
-#define OPTION_FP64 (OPTION_MISC_BASE + 9)
+#define OPTION_FP64 (OPTION_MISC_BASE + 8)
   {"mfp64", no_argument, NULL, OPTION_FP64},
-#define OPTION_GP64 (OPTION_MISC_BASE + 10)
+#define OPTION_GP64 (OPTION_MISC_BASE + 9)
   {"mgp64", no_argument, NULL, OPTION_GP64},
-#define OPTION_RELAX_BRANCH (OPTION_MISC_BASE + 11)
-#define OPTION_NO_RELAX_BRANCH (OPTION_MISC_BASE + 12)
+#define OPTION_RELAX_BRANCH (OPTION_MISC_BASE + 10)
+#define OPTION_NO_RELAX_BRANCH (OPTION_MISC_BASE + 11)
   {"relax-branch", no_argument, NULL, OPTION_RELAX_BRANCH},
   {"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
 
   /* ELF-specific options.  */
 #ifdef OBJ_ELF
-#define OPTION_ELF_BASE    (OPTION_MISC_BASE + 13)
+#define OPTION_ELF_BASE    (OPTION_MISC_BASE + 12)
 #define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
   {"KPIC",        no_argument, NULL, OPTION_CALL_SHARED},
   {"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
@@ -10721,22 +10300,12 @@ md_parse_option (int c, char *arg)
       mips_opts.ase_mips3d = 0;
       break;
 
-    case OPTION_MEMBEDDED_PIC:
-      mips_pic = EMBEDDED_PIC;
-      if (USE_GLOBAL_POINTER_OPT && g_switch_seen)
-       {
-         as_bad (_("-G may not be used with embedded PIC code"));
-         return 0;
-       }
-      g_switch_value = 0x7fffffff;
-      break;
-
-    case OPTION_FIX_VR4122:
-      mips_fix_4122_bugs = 1;
+    case OPTION_FIX_VR4120:
+      mips_fix_vr4120 = 1;
       break;
 
-    case OPTION_NO_FIX_VR4122:
-      mips_fix_4122_bugs = 0;
+    case OPTION_NO_FIX_VR4120:
+      mips_fix_vr4120 = 0;
       break;
 
     case OPTION_RELAX_BRANCH:
@@ -10786,14 +10355,9 @@ md_parse_option (int c, char *arg)
 #endif /* OBJ_ELF */
 
     case 'G':
-      if (! USE_GLOBAL_POINTER_OPT)
-       {
-         as_bad (_("-G is not supported for this configuration"));
-         return 0;
-       }
-      else if (mips_pic == SVR4_PIC || mips_pic == EMBEDDED_PIC)
+      if (mips_pic == SVR4_PIC)
        {
-         as_bad (_("-G may not be used with SVR4 or embedded PIC code"));
+         as_bad (_("-G may not be used with SVR4 PIC code"));
          return 0;
        }
       else
@@ -11110,10 +10674,53 @@ mips_frob_file_before_adjust (void)
 #endif
 }
 
-/* Sort any unmatched HI16_S relocs so that they immediately precede
-   the corresponding LO reloc.  This is called before md_apply_fix3 and
-   tc_gen_reloc.  Unmatched HI16_S relocs can only be generated by
-   explicit use of the %hi modifier.  */
+/* Sort any unmatched HI16 and GOT16 relocs so that they immediately precede
+   the corresponding LO16 reloc.  This is called before md_apply_fix3 and
+   tc_gen_reloc.  Unmatched relocs can only be generated by use of explicit
+   relocation operators.
+
+   For our purposes, a %lo() expression matches a %got() or %hi()
+   expression if:
+
+      (a) it refers to the same symbol; and
+      (b) the offset applied in the %lo() expression is no lower than
+         the offset applied in the %got() or %hi().
+
+   (b) allows us to cope with code like:
+
+       lui     $4,%hi(foo)
+       lh      $4,%lo(foo+2)($4)
+
+   ...which is legal on RELA targets, and has a well-defined behaviour
+   if the user knows that adding 2 to "foo" will not induce a carry to
+   the high 16 bits.
+
+   When several %lo()s match a particular %got() or %hi(), we use the
+   following rules to distinguish them:
+
+     (1) %lo()s with smaller offsets are a better match than %lo()s with
+         higher offsets.
+
+     (2) %lo()s with no matching %got() or %hi() are better than those
+         that already have a matching %got() or %hi().
+
+     (3) later %lo()s are better than earlier %lo()s.
+
+   These rules are applied in order.
+
+   (1) means, among other things, that %lo()s with identical offsets are
+   chosen if they exist.
+
+   (2) means that we won't associate several high-part relocations with
+   the same low-part relocation unless there's no alternative.  Having
+   several high parts for the same low part is a GNU extension; this rule
+   allows careful users to avoid it.
+
+   (3) is purely cosmetic.  mips_hi_fixup_list is is in reverse order,
+   with the last high-part relocation being at the front of the list.
+   It therefore makes sense to choose the last matching low-part
+   relocation, all other things being equal.  It's also easier
+   to code that way.  */
 
 void
 mips_frob_file (void)
@@ -11123,7 +10730,8 @@ mips_frob_file (void)
   for (l = mips_hi_fixup_list; l != NULL; l = l->next)
     {
       segment_info_type *seginfo;
-      int pass;
+      bfd_boolean matched_lo_p;
+      fixS **hi_pos, **lo_pos, **pos;
 
       assert (reloc_needs_lo_p (l->fixp->fx_r_type));
 
@@ -11137,81 +10745,56 @@ mips_frob_file (void)
       if (fixup_has_matching_lo_p (l->fixp))
        continue;
 
-      /* Look through the fixups for this segment for a matching %lo.
-         When we find one, move the %hi just in front of it.  We do
-         this in two passes.  In the first pass, we try to find a
-         unique %lo.  In the second pass, we permit multiple %hi
-         relocs for a single %lo (this is a GNU extension).  */
       seginfo = seg_info (l->seg);
-      for (pass = 0; pass < 2; pass++)
-       {
-         fixS *f, *prev;
 
-         prev = NULL;
-         for (f = seginfo->fix_root; f != NULL; f = f->fx_next)
+      /* Set HI_POS to the position of this relocation in the chain.
+        Set LO_POS to the position of the chosen low-part relocation.
+        MATCHED_LO_P is true on entry to the loop if *POS is a low-part
+        relocation that matches an immediately-preceding high-part
+        relocation.  */
+      hi_pos = NULL;
+      lo_pos = NULL;
+      matched_lo_p = FALSE;
+      for (pos = &seginfo->fix_root; *pos != NULL; pos = &(*pos)->fx_next)
+       {
+         if (*pos == l->fixp)
+           hi_pos = pos;
+
+         if ((*pos)->fx_r_type == BFD_RELOC_LO16
+             && (*pos)->fx_addsy == l->fixp->fx_addsy
+             && (*pos)->fx_offset >= l->fixp->fx_offset
+             && (lo_pos == NULL
+                 || (*pos)->fx_offset < (*lo_pos)->fx_offset
+                 || (!matched_lo_p
+                     && (*pos)->fx_offset == (*lo_pos)->fx_offset)))
+           lo_pos = pos;
+
+         matched_lo_p = (reloc_needs_lo_p ((*pos)->fx_r_type)
+                         && fixup_has_matching_lo_p (*pos));
+       }
+
+      /* If we found a match, remove the high-part relocation from its
+        current position and insert it before the low-part relocation.
+        Make the offsets match so that fixup_has_matching_lo_p()
+        will return true.
+
+        We don't warn about unmatched high-part relocations since some
+        versions of gcc have been known to emit dead "lui ...%hi(...)"
+        instructions.  */
+      if (lo_pos != NULL)
+       {
+         l->fixp->fx_offset = (*lo_pos)->fx_offset;
+         if (l->fixp->fx_next != *lo_pos)
            {
-             /* Check whether this is a %lo fixup which matches l->fixp.  */
-             if (f->fx_r_type == BFD_RELOC_LO16
-                 && f->fx_addsy == l->fixp->fx_addsy
-                 && f->fx_offset == l->fixp->fx_offset
-                 && (pass == 1
-                     || prev == NULL
-                     || !reloc_needs_lo_p (prev->fx_r_type)
-                     || !fixup_has_matching_lo_p (prev)))
-               {
-                 fixS **pf;
-
-                 /* Move l->fixp before f.  */
-                 for (pf = &seginfo->fix_root;
-                      *pf != l->fixp;
-                      pf = &(*pf)->fx_next)
-                   assert (*pf != NULL);
-
-                 *pf = l->fixp->fx_next;
-
-                 l->fixp->fx_next = f;
-                 if (prev == NULL)
-                   seginfo->fix_root = l->fixp;
-                 else
-                   prev->fx_next = l->fixp;
-
-                 break;
-               }
-
-             prev = f;
+             *hi_pos = l->fixp->fx_next;
+             l->fixp->fx_next = *lo_pos;
+             *lo_pos = l->fixp;
            }
-
-         if (f != NULL)
-           break;
-
-#if 0 /* GCC code motion plus incomplete dead code elimination
-        can leave a %hi without a %lo.  */
-         if (pass == 1)
-           as_warn_where (l->fixp->fx_file, l->fixp->fx_line,
-                          _("Unmatched %%hi reloc"));
-#endif
        }
     }
 }
 
-/* When generating embedded PIC code we need to use a special
-   relocation to represent the difference of two symbols in the .text
-   section (switch tables use a difference of this sort).  See
-   include/coff/mips.h for details.  This macro checks whether this
-   fixup requires the special reloc.  */
-#define SWITCH_TABLE(fixp) \
-  ((fixp)->fx_r_type == BFD_RELOC_32 \
-   && OUTPUT_FLAVOR != bfd_target_elf_flavour \
-   && (fixp)->fx_addsy != NULL \
-   && (fixp)->fx_subsy != NULL \
-   && S_GET_SEGMENT ((fixp)->fx_addsy) == text_section \
-   && S_GET_SEGMENT ((fixp)->fx_subsy) == text_section)
-
-/* When generating embedded PIC code we must keep all PC relative
-   relocations, in case the linker has to relax a call.  We also need
-   to keep relocations for switch table entries.
-
-   We may have combined relocations without symbols in the N32/N64 ABI.
+/* We may have combined relocations without symbols in the N32/N64 ABI.
    We have to prevent gas from dropping them.  */
 
 int
@@ -11227,11 +10810,7 @@ mips_force_relocation (fixS *fixp)
          || fixp->fx_r_type == BFD_RELOC_LO16))
     return 1;
 
-  return (mips_pic == EMBEDDED_PIC
-         && (fixp->fx_pcrel
-             || SWITCH_TABLE (fixp)
-             || fixp->fx_r_type == BFD_RELOC_PCREL_HI16_S
-             || fixp->fx_r_type == BFD_RELOC_PCREL_LO16));
+  return 0;
 }
 
 /* This hook is called before a fix is simplified.  We don't really
@@ -11271,9 +10850,8 @@ mips_validate_fix (struct fix *fixP, asection *seg)
      whole function).  */
 
   if (fixP->fx_r_type == BFD_RELOC_16_PCREL_S2
-      && (((OUTPUT_FLAVOR == bfd_target_ecoff_flavour
-           || OUTPUT_FLAVOR == bfd_target_elf_flavour)
-          && mips_pic != EMBEDDED_PIC)
+      && ((OUTPUT_FLAVOR == bfd_target_ecoff_flavour
+          || OUTPUT_FLAVOR == bfd_target_elf_flavour)
          || bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16_PCREL_S2) == NULL)
       && fixP->fx_addsy)
     {
@@ -11338,7 +10916,8 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
   buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
 
   /* We are not done if this is a composite relocation to set up gp.  */
-  if (fixP->fx_addsy == NULL && ! fixP->fx_pcrel
+  assert (! fixP->fx_pcrel);
+  if (fixP->fx_addsy == NULL
       && !(fixP->fx_r_type == BFD_RELOC_MIPS_SUB
           || (fixP->fx_r_type == BFD_RELOC_64
               && (previous_fx_r_type == BFD_RELOC_GPREL32
@@ -11379,9 +10958,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_MIPS_CALL_HI16:
     case BFD_RELOC_MIPS_CALL_LO16:
     case BFD_RELOC_MIPS16_GPREL:
-      if (fixP->fx_pcrel)
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("Invalid PC relative reloc"));
+      assert (! fixP->fx_pcrel);
       /* Nothing needed to do. The value comes from the reloc entry */
       break;
 
@@ -11392,44 +10969,10 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       *valP = 0;
       break;
 
-    case BFD_RELOC_PCREL_HI16_S:
-      /* The addend for this is tricky if it is internal, so we just
-        do everything here rather than in bfd_install_relocation.  */
-      if (OUTPUT_FLAVOR == bfd_target_elf_flavour && !fixP->fx_done)
-       break;
-      if (fixP->fx_addsy
-         && (symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_SECTION_SYM) == 0)
-       {
-         /* For an external symbol adjust by the address to make it
-            pcrel_offset.  We use the address of the RELLO reloc
-            which follows this one.  */
-         *valP += (fixP->fx_next->fx_frag->fr_address
-                   + fixP->fx_next->fx_where);
-       }
-      *valP = ((*valP + 0x8000) >> 16) & 0xffff;
-      if (target_big_endian)
-       buf += 2;
-      md_number_to_chars (buf, *valP, 2);
-      break;
-
-    case BFD_RELOC_PCREL_LO16:
-      /* The addend for this is tricky if it is internal, so we just
-        do everything here rather than in bfd_install_relocation.  */
-      if (OUTPUT_FLAVOR == bfd_target_elf_flavour && !fixP->fx_done)
-       break;
-      if (fixP->fx_addsy
-         && (symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_SECTION_SYM) == 0)
-       *valP += fixP->fx_frag->fr_address + fixP->fx_where;
-      if (target_big_endian)
-       buf += 2;
-      md_number_to_chars (buf, *valP, 2);
-      break;
-
     case BFD_RELOC_64:
       /* This is handled like BFD_RELOC_32, but we output a sign
          extended value if we are only 32 bits.  */
-      if (fixP->fx_done
-         || (mips_pic == EMBEDDED_PIC && SWITCH_TABLE (fixP)))
+      if (fixP->fx_done)
        {
          if (8 <= sizeof (valueT))
            md_number_to_chars (buf, *valP, 8);
@@ -11453,11 +10996,8 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_32:
       /* If we are deleting this reloc entry, we must fill in the
         value now.  This can happen if we have a .word which is not
-        resolved when it appears but is later defined.  We also need
-        to fill in the value if this is an embedded PIC switch table
-        entry.  */
-      if (fixP->fx_done
-         || (mips_pic == EMBEDDED_PIC && SWITCH_TABLE (fixP)))
+        resolved when it appears but is later defined.   */
+      if (fixP->fx_done)
        md_number_to_chars (buf, *valP, 4);
       break;
 
@@ -11470,6 +11010,8 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       break;
 
     case BFD_RELOC_LO16:
+      /* FIXME: Now that embedded-PIC is gone, some of this code/comment
+        may be safe to remove, but if so it's not obvious.  */
       /* When handling an embedded PIC switch statement, we can wind
         up deleting a LO16 reloc.  See the 'o' case in mips_ip.  */
       if (fixP->fx_done)
@@ -11511,7 +11053,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
               && fixP->fx_done
               && fixP->fx_frag->fr_address >= text_section->vma
               && (fixP->fx_frag->fr_address
-                  < text_section->vma + text_section->_raw_size)
+                  < text_section->vma + bfd_get_section_size (text_section))
               && ((insn & 0xffff0000) == 0x10000000     /* beq $0,$0 */
                   || (insn & 0xffff0000) == 0x04010000  /* bgez $0 */
                   || (insn & 0xffff0000) == 0x04110000)) /* bgezal $0 */
@@ -11740,13 +11282,6 @@ s_change_sec (int sec)
 {
   segT seg;
 
-  /* When generating embedded PIC code, we only use the .text, .lit8,
-     .sdata and .sbss sections.  We change the .data and .rdata
-     pseudo-ops to use .sdata.  */
-  if (mips_pic == EMBEDDED_PIC
-      && (sec == 'd' || sec == 'r'))
-    sec = 's';
-
 #ifdef OBJ_ELF
   /* The ELF backend needs to know that we are changing sections, so
      that .previous works correctly.  We could do something like check
@@ -11772,52 +11307,30 @@ s_change_sec (int sec)
       break;
 
     case 'r':
-      if (USE_GLOBAL_POINTER_OPT)
-       {
-         seg = subseg_new (RDATA_SECTION_NAME,
-                           (subsegT) get_absolute_expression ());
-         if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
-           {
-             bfd_set_section_flags (stdoutput, seg,
-                                    (SEC_ALLOC
-                                     | SEC_LOAD
-                                     | SEC_READONLY
-                                     | SEC_RELOC
-                                     | SEC_DATA));
-             if (strcmp (TARGET_OS, "elf") != 0)
-               record_alignment (seg, 4);
-           }
-         demand_empty_rest_of_line ();
-       }
-      else
+      seg = subseg_new (RDATA_SECTION_NAME,
+                       (subsegT) get_absolute_expression ());
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
        {
-         as_bad (_("No read only data section in this object file format"));
-         demand_empty_rest_of_line ();
-         return;
+         bfd_set_section_flags (stdoutput, seg, (SEC_ALLOC | SEC_LOAD
+                                                 | SEC_READONLY | SEC_RELOC
+                                                 | SEC_DATA));
+         if (strcmp (TARGET_OS, "elf") != 0)
+           record_alignment (seg, 4);
        }
+      demand_empty_rest_of_line ();
       break;
 
     case 's':
-      if (USE_GLOBAL_POINTER_OPT)
-       {
-         seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
-         if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
-           {
-             bfd_set_section_flags (stdoutput, seg,
-                                    SEC_ALLOC | SEC_LOAD | SEC_RELOC
-                                    | SEC_DATA);
-             if (strcmp (TARGET_OS, "elf") != 0)
-               record_alignment (seg, 4);
-           }
-         demand_empty_rest_of_line ();
-         break;
-       }
-      else
+      seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
        {
-         as_bad (_("Global pointers not supported; recompile -G 0"));
-         demand_empty_rest_of_line ();
-         return;
+         bfd_set_section_flags (stdoutput, seg,
+                                SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
+         if (strcmp (TARGET_OS, "elf") != 0)
+           record_alignment (seg, 4);
        }
+      demand_empty_rest_of_line ();
+      break;
     }
 
   auto_align = 1;
@@ -12013,7 +11526,7 @@ s_option (int x ATTRIBUTE_UNUSED)
       else
        as_bad (_(".option pic%d not supported"), i);
 
-      if (USE_GLOBAL_POINTER_OPT && mips_pic == SVR4_PIC)
+      if (mips_pic == SVR4_PIC)
        {
          if (g_switch_seen && g_switch_value != 0)
            as_warn (_("-G may not be used with SVR4 PIC code"));
@@ -12123,34 +11636,11 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
 
       /* Permit the user to change the ISA and architecture on the fly.
         Needless to say, misuse can cause serious problems.  */
-      if (strcmp (name, "mips0") == 0)
+      if (strcmp (name, "mips0") == 0 || strcmp (name, "arch=default") == 0)
        {
          reset = 1;
          mips_opts.isa = file_mips_isa;
-       }
-      else if (strcmp (name, "mips1") == 0)
-       mips_opts.isa = ISA_MIPS1;
-      else if (strcmp (name, "mips2") == 0)
-       mips_opts.isa = ISA_MIPS2;
-      else if (strcmp (name, "mips3") == 0)
-       mips_opts.isa = ISA_MIPS3;
-      else if (strcmp (name, "mips4") == 0)
-       mips_opts.isa = ISA_MIPS4;
-      else if (strcmp (name, "mips5") == 0)
-       mips_opts.isa = ISA_MIPS5;
-      else if (strcmp (name, "mips32") == 0)
-       mips_opts.isa = ISA_MIPS32;
-      else if (strcmp (name, "mips32r2") == 0)
-       mips_opts.isa = ISA_MIPS32R2;
-      else if (strcmp (name, "mips64") == 0)
-       mips_opts.isa = ISA_MIPS64;
-      else if (strcmp (name, "mips64r2") == 0)
-       mips_opts.isa = ISA_MIPS64R2;
-      else if (strcmp (name, "arch=default") == 0)
-       {
-         reset = 1;
          mips_opts.arch = file_mips_arch;
-         mips_opts.isa = file_mips_isa;
        }
       else if (strncmp (name, "arch=", 5) == 0)
        {
@@ -12165,8 +11655,21 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
              mips_opts.isa = p->isa;
            }
        }
+      else if (strncmp (name, "mips", 4) == 0)
+       {
+         const struct mips_cpu_info *p;
+
+         p = mips_parse_cpu("internal use", name);
+         if (!p)
+           as_bad (_("unknown ISA level %s"), name + 4);
+         else
+           {
+             mips_opts.arch = p->cpu;
+             mips_opts.isa = p->isa;
+           }
+       }
       else
-       as_bad (_("unknown ISA level %s"), name + 4);
+       as_bad (_("unknown ISA or architecture %s"), name);
 
       switch (mips_opts.isa)
        {
@@ -12254,12 +11757,11 @@ s_abicalls (int ignore ATTRIBUTE_UNUSED)
 {
   mips_pic = SVR4_PIC;
   mips_abicalls = TRUE;
-  if (USE_GLOBAL_POINTER_OPT)
-    {
-      if (g_switch_seen && g_switch_value != 0)
-       as_warn (_("-G may not be used with SVR4 PIC code"));
-      g_switch_value = 0;
-    }
+
+  if (g_switch_seen && g_switch_value != 0)
+    as_warn (_("-G may not be used with SVR4 PIC code"));
+  g_switch_value = 0;
+
   bfd_set_gp_size (stdoutput, 0);
   demand_empty_rest_of_line ();
 }
@@ -12278,7 +11780,6 @@ static void
 s_cpload (int ignore ATTRIBUTE_UNUSED)
 {
   expressionS ex;
-  int icnt = 0;
 
   /* If we are not generating SVR4 PIC code, or if this is NewABI code,
      .cpload is ignored.  */
@@ -12300,12 +11801,13 @@ s_cpload (int ignore ATTRIBUTE_UNUSED)
   /* In ELF, this symbol is implicitly an STT_OBJECT symbol.  */
   symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT;
 
-  macro_build_lui (NULL, &icnt, &ex, mips_gp_register);
-  macro_build (NULL, &icnt, &ex, "addiu", "t,r,j", mips_gp_register,
+  macro_start ();
+  macro_build_lui (&ex, mips_gp_register);
+  macro_build (&ex, "addiu", "t,r,j", mips_gp_register,
               mips_gp_register, BFD_RELOC_LO16);
-
-  macro_build (NULL, &icnt, NULL, "addu", "d,v,t", mips_gp_register,
+  macro_build (NULL, "addu", "d,v,t", mips_gp_register,
               mips_gp_register, tc_get_register (0));
+  macro_end ();
 
   demand_empty_rest_of_line ();
 }
@@ -12331,7 +11833,6 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
   expressionS ex_off;
   expressionS ex_sym;
   int reg1;
-  int icnt = 0;
   char *f;
 
   /* If we are not generating SVR4 PIC code, .cpsetup is ignored.
@@ -12373,6 +11874,7 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
   SKIP_WHITESPACE ();
   expression (&ex_sym);
 
+  macro_start ();
   if (mips_cpreturn_register == -1)
     {
       ex_off.X_op = O_constant;
@@ -12380,34 +11882,34 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
       ex_off.X_op_symbol = NULL;
       ex_off.X_add_number = mips_cpreturn_offset;
 
-      macro_build (NULL, &icnt, &ex_off, "sd", "t,o(b)", mips_gp_register,
+      macro_build (&ex_off, "sd", "t,o(b)", mips_gp_register,
                   BFD_RELOC_LO16, SP);
     }
   else
-    macro_build (NULL, &icnt, NULL, "daddu", "d,v,t", mips_cpreturn_register,
+    macro_build (NULL, "daddu", "d,v,t", mips_cpreturn_register,
                 mips_gp_register, 0);
 
   /* Ensure there's room for the next two instructions, so that `f'
      doesn't end up with an address in the wrong frag.  */
   frag_grow (8);
   f = frag_more (0);
-  macro_build (NULL, &icnt, &ex_sym, "lui", "t,u", mips_gp_register,
-              BFD_RELOC_GPREL16);
+  macro_build (&ex_sym, "lui", "t,u", mips_gp_register, BFD_RELOC_GPREL16);
   fix_new (frag_now, f - frag_now->fr_literal,
           8, NULL, 0, 0, BFD_RELOC_MIPS_SUB);
   fix_new (frag_now, f - frag_now->fr_literal,
           4, NULL, 0, 0, BFD_RELOC_HI16_S);
 
   f = frag_more (0);
-  macro_build (NULL, &icnt, &ex_sym, "addiu", "t,r,j", mips_gp_register,
+  macro_build (&ex_sym, "addiu", "t,r,j", mips_gp_register,
               mips_gp_register, BFD_RELOC_GPREL16);
   fix_new (frag_now, f - frag_now->fr_literal,
           8, NULL, 0, 0, BFD_RELOC_MIPS_SUB);
   fix_new (frag_now, f - frag_now->fr_literal,
           4, NULL, 0, 0, BFD_RELOC_LO16);
 
-  macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t", mips_gp_register,
+  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", mips_gp_register,
               mips_gp_register, reg1);
+  macro_end ();
 
   demand_empty_rest_of_line ();
 }
@@ -12435,7 +11937,6 @@ static void
 s_cprestore (int ignore ATTRIBUTE_UNUSED)
 {
   expressionS ex;
-  int icnt = 0;
 
   /* If we are not generating SVR4 PIC code, or if this is NewABI code,
      .cprestore is ignored.  */
@@ -12453,8 +11954,10 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED)
   ex.X_op_symbol = NULL;
   ex.X_add_number = mips_cprestore_offset;
 
-  macro_build_ldst_constoffset (NULL, &icnt, &ex, ADDRESS_STORE_INSN,
-                               mips_gp_register, SP, HAVE_64BIT_ADDRESSES);
+  macro_start ();
+  macro_build_ldst_constoffset (&ex, ADDRESS_STORE_INSN, mips_gp_register,
+                               SP, HAVE_64BIT_ADDRESSES);
+  macro_end ();
 
   demand_empty_rest_of_line ();
 }
@@ -12470,7 +11973,6 @@ static void
 s_cpreturn (int ignore ATTRIBUTE_UNUSED)
 {
   expressionS ex;
-  int icnt = 0;
 
   /* If we are not generating SVR4 PIC code, .cpreturn is ignored.
      We also need NewABI support.  */
@@ -12480,6 +11982,7 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
+  macro_start ();
   if (mips_cpreturn_register == -1)
     {
       ex.X_op = O_constant;
@@ -12487,12 +11990,12 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
       ex.X_op_symbol = NULL;
       ex.X_add_number = mips_cpreturn_offset;
 
-      macro_build (NULL, &icnt, &ex, "ld", "t,o(b)", mips_gp_register,
-                  BFD_RELOC_LO16, SP);
+      macro_build (&ex, "ld", "t,o(b)", mips_gp_register, BFD_RELOC_LO16, SP);
     }
   else
-    macro_build (NULL, &icnt, NULL, "daddu", "d,v,t", mips_gp_register,
+    macro_build (NULL, "daddu", "d,v,t", mips_gp_register,
                 mips_cpreturn_register, 0);
+  macro_end ();
 
   demand_empty_rest_of_line ();
 }
@@ -12604,7 +12107,6 @@ s_gpdword (int ignore ATTRIBUTE_UNUSED)
 static void
 s_cpadd (int ignore ATTRIBUTE_UNUSED)
 {
-  int icnt = 0;
   int reg;
 
   /* This is ignored when not generating SVR4 PIC code.  */
@@ -12615,9 +12117,10 @@ s_cpadd (int ignore ATTRIBUTE_UNUSED)
     }
 
   /* Add $gp to the register named as an argument.  */
+  macro_start ();
   reg = tc_get_register (0);
-  macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
-              reg, reg, mips_gp_register);
+  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", reg, reg, mips_gp_register);
+  macro_end ();
 
   demand_empty_rest_of_line ();
 }
@@ -12815,7 +12318,7 @@ nopic_need_relax (symbolS *sym, int before_relaxing)
   if (sym == 0)
     return 0;
 
-  if (USE_GLOBAL_POINTER_OPT && g_switch_value > 0)
+  if (g_switch_value > 0)
     {
       const char *symname;
       int change;
@@ -12922,9 +12425,7 @@ pic_need_relax (symbolS *sym, asection *segtype)
 #ifdef OBJ_ELF
          /* A global or weak symbol is treated as external.  */
          && (OUTPUT_FLAVOR != bfd_target_elf_flavour
-             || (! S_IS_WEAK (sym)
-                 && (! S_IS_EXTERNAL (sym)
-                     || mips_pic == EMBEDDED_PIC)))
+             || (! S_IS_WEAK (sym) && ! S_IS_EXTERNAL (sym)))
 #endif
          );
 }
@@ -13224,34 +12725,21 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype)
 
   if (change)
     {
-      /* Record the offset to the first reloc in the fr_opcode field.
-        This lets md_convert_frag and tc_gen_reloc know that the code
-        must be expanded.  */
-      fragp->fr_opcode = (fragp->fr_literal
-                         + fragp->fr_fix
-                         - RELAX_OLD (fragp->fr_subtype)
-                         + RELAX_RELOC1 (fragp->fr_subtype));
-      /* FIXME: This really needs as_warn_where.  */
-      if (RELAX_WARN (fragp->fr_subtype))
-       as_warn (_("AT used after \".set noat\" or macro used after "
-                  "\".set nomacro\""));
-
-      return RELAX_NEW (fragp->fr_subtype) - RELAX_OLD (fragp->fr_subtype);
+      fragp->fr_subtype |= RELAX_USE_SECOND;
+      return -RELAX_FIRST (fragp->fr_subtype);
     }
-
-  return 0;
+  else
+    return -RELAX_SECOND (fragp->fr_subtype);
 }
 
 /* This is called to see whether a reloc against a defined symbol
-   should be converted into a reloc against a section.  Don't adjust
-   MIPS16 jump relocations, so we don't have to worry about the format
-   of the offset in the .o file.  Don't adjust relocations against
-   mips16 symbols, so that the linker can find them if it needs to set
-   up a stub.  */
+   should be converted into a reloc against a section.  */
 
 int
 mips_fix_adjustable (fixS *fixp)
 {
+  /* Don't adjust MIPS16 jump relocations, so we don't have to worry
+     about the format of the offset in the .o file. */
   if (fixp->fx_r_type == BFD_RELOC_MIPS16_JMP)
     return 0;
 
@@ -13262,7 +12750,28 @@ mips_fix_adjustable (fixS *fixp)
   if (fixp->fx_addsy == NULL)
     return 1;
 
+  /* If symbol SYM is in a mergeable section, relocations of the form
+     SYM + 0 can usually be made section-relative.  The mergeable data
+     is then identified by the section offset rather than by the symbol.
+
+     However, if we're generating REL LO16 relocations, the offset is split
+     between the LO16 and parterning high part relocation.  The linker will
+     need to recalculate the complete offset in order to correctly identify
+     the merge data.
+
+     The linker has traditionally not looked for the parterning high part
+     relocation, and has thus allowed orphaned R_MIPS_LO16 relocations to be
+     placed anywhere.  Rather than break backwards compatibility by changing
+     this, it seems better not to force the issue, and instead keep the
+     original symbol.  This will work with either linker behavior.  */
+  if ((fixp->fx_r_type == BFD_RELOC_LO16 || reloc_needs_lo_p (fixp->fx_r_type))
+      && HAVE_IN_PLACE_ADDENDS
+      && (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE) != 0)
+    return 0;
+
 #ifdef OBJ_ELF
+  /* Don't adjust relocations against mips16 symbols, so that the linker
+     can find them if it needs to set up a stub.  */
   if (OUTPUT_FLAVOR == bfd_target_elf_flavour
       && S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16
       && fixp->fx_subsy == NULL)
@@ -13288,166 +12797,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
-  if (mips_pic == EMBEDDED_PIC
-      && SWITCH_TABLE (fixp))
-    {
-      /* For a switch table entry we use a special reloc.  The addend
-        is actually the difference between the reloc address and the
-        subtrahend.  */
-      reloc->addend = reloc->address - S_GET_VALUE (fixp->fx_subsy);
-      if (OUTPUT_FLAVOR != bfd_target_ecoff_flavour)
-       as_fatal (_("Double check fx_r_type in tc-mips.c:tc_gen_reloc"));
-      fixp->fx_r_type = BFD_RELOC_GPREL32;
-    }
-  else if (fixp->fx_pcrel)
-    {
-      bfd_vma pcrel_address;
-
-      /* Set PCREL_ADDRESS to this relocation's "PC".  The PC for high
-        high-part relocs is the address of the low-part reloc.  */
-      if (fixp->fx_r_type == BFD_RELOC_PCREL_HI16_S)
-       {
-         assert (fixp->fx_next != NULL
-                 && fixp->fx_next->fx_r_type == BFD_RELOC_PCREL_LO16);
-         pcrel_address = (fixp->fx_next->fx_where
-                          + fixp->fx_next->fx_frag->fr_address);
-       }
-      else
-       pcrel_address = reloc->address;
-
-      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
-       {
-         /* At this point, fx_addnumber is "symbol offset - pcrel_address".
-            Relocations want only the symbol offset.  */
-         reloc->addend = fixp->fx_addnumber + pcrel_address;
-       }
-      else if (fixp->fx_r_type == BFD_RELOC_PCREL_LO16
-              || fixp->fx_r_type == BFD_RELOC_PCREL_HI16_S)
-       {
-         /* We use a special addend for an internal RELLO or RELHI reloc.  */
-         if (symbol_section_p (fixp->fx_addsy))
-           reloc->addend = pcrel_address - S_GET_VALUE (fixp->fx_subsy);
-         else
-           reloc->addend = fixp->fx_addnumber + pcrel_address;
-       }
-      else
-       {
-         if (OUTPUT_FLAVOR != bfd_target_aout_flavour)
-           /* A gruesome hack which is a result of the gruesome gas reloc
-              handling.  */
-           reloc->addend = pcrel_address;
-         else
-           reloc->addend = -pcrel_address;
-       }
-    }
-  else
-    reloc->addend = fixp->fx_addnumber;
-
-  /* If this is a variant frag, we may need to adjust the existing
-     reloc and generate a new one.  */
-  if (fixp->fx_frag->fr_opcode != NULL
-      && ((fixp->fx_r_type == BFD_RELOC_GPREL16
-          && ! HAVE_NEWABI)
-         || (fixp->fx_r_type == BFD_RELOC_MIPS_GOT_DISP
-             && HAVE_NEWABI)
-         || fixp->fx_r_type == BFD_RELOC_MIPS_GOT16
-         || fixp->fx_r_type == BFD_RELOC_MIPS_CALL16
-         || fixp->fx_r_type == BFD_RELOC_MIPS_GOT_HI16
-         || fixp->fx_r_type == BFD_RELOC_MIPS_GOT_LO16
-         || fixp->fx_r_type == BFD_RELOC_MIPS_CALL_HI16
-         || fixp->fx_r_type == BFD_RELOC_MIPS_CALL_LO16)
-    )
-    {
-      arelent *reloc2;
-
-      assert (! RELAX_MIPS16_P (fixp->fx_frag->fr_subtype));
-
-      /* If this is not the last reloc in this frag, then we have two
-        GPREL relocs, or a GOT_HI16/GOT_LO16 pair, or a
-        CALL_HI16/CALL_LO16, both of which are being replaced.  Let
-        the second one handle all of them.  */
-      if (fixp->fx_next != NULL
-         && fixp->fx_frag == fixp->fx_next->fx_frag)
-       {
-         assert ((fixp->fx_r_type == BFD_RELOC_GPREL16
-                  && fixp->fx_next->fx_r_type == BFD_RELOC_GPREL16)
-                 || (fixp->fx_r_type == BFD_RELOC_MIPS_GOT_HI16
-                     && (fixp->fx_next->fx_r_type
-                         == BFD_RELOC_MIPS_GOT_LO16))
-                 || (fixp->fx_r_type == BFD_RELOC_MIPS_CALL_HI16
-                     && (fixp->fx_next->fx_r_type
-                         == BFD_RELOC_MIPS_CALL_LO16)));
-         retval[0] = NULL;
-         return retval;
-       }
-
-      fixp->fx_where = fixp->fx_frag->fr_opcode - fixp->fx_frag->fr_literal;
-      reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
-      reloc->addend += fixp->fx_frag->tc_frag_data.tc_fr_offset;
-      reloc2 = retval[1] = (arelent *) xmalloc (sizeof (arelent));
-      reloc2->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
-      *reloc2->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
-      reloc2->address = (reloc->address
-                        + (RELAX_RELOC2 (fixp->fx_frag->fr_subtype)
-                           - RELAX_RELOC1 (fixp->fx_frag->fr_subtype)));
-      reloc2->addend = reloc->addend;
-      reloc2->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO16);
-      assert (reloc2->howto != NULL);
-
-      if (RELAX_RELOC3 (fixp->fx_frag->fr_subtype))
-       {
-         arelent *reloc3;
-
-         reloc3 = retval[2] = (arelent *) xmalloc (sizeof (arelent));
-         *reloc3 = *reloc2;
-         reloc3->address += 4;
-       }
-
-      if (mips_pic == NO_PIC)
-       {
-         assert (fixp->fx_r_type == BFD_RELOC_GPREL16);
-         fixp->fx_r_type = BFD_RELOC_HI16_S;
-       }
-      else if (mips_pic == SVR4_PIC)
-       {
-         switch (fixp->fx_r_type)
-           {
-           default:
-             abort ();
-           case BFD_RELOC_MIPS_GOT16:
-             break;
-           case BFD_RELOC_MIPS_GOT_LO16:
-           case BFD_RELOC_MIPS_CALL_LO16:
-             if (HAVE_NEWABI)
-               {
-                 fixp->fx_r_type = BFD_RELOC_MIPS_GOT_PAGE;
-                 reloc2->howto = bfd_reloc_type_lookup
-                   (stdoutput, BFD_RELOC_MIPS_GOT_OFST);
-               }
-             else
-               fixp->fx_r_type = BFD_RELOC_MIPS_GOT16;
-             break;
-           case BFD_RELOC_MIPS_CALL16:
-           case BFD_RELOC_MIPS_GOT_OFST:
-           case BFD_RELOC_MIPS_GOT_DISP:
-             if (HAVE_NEWABI)
-               {
-                 /* It may seem nonsensical to relax GOT_DISP to
-                    GOT_DISP, but we're actually turning a GOT_DISP
-                    without offset into a GOT_DISP with an offset,
-                    getting rid of the separate addition, which we can
-                    do when the symbol is found to be local.  */
-                 fixp->fx_r_type = BFD_RELOC_MIPS_GOT_DISP;
-                 retval[1] = NULL;
-               }
-             else
-               fixp->fx_r_type = BFD_RELOC_MIPS_GOT16;
-             break;
-           }
-       }
-      else
-       abort ();
-    }
+  assert (! fixp->fx_pcrel);
+  reloc->addend = fixp->fx_addnumber;
 
   /* Since the old MIPS ELF ABI uses Rel instead of Rela, encode the vtable
      entry to be used in the relocation's section offset.  */
@@ -13457,49 +12808,16 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
       reloc->addend = 0;
     }
 
-  /* Since DIFF_EXPR_OK is defined in tc-mips.h, it is possible that
-     fixup_segment converted a non-PC relative reloc into a PC
-     relative reloc.  In such a case, we need to convert the reloc
-     code.  */
   code = fixp->fx_r_type;
-  if (fixp->fx_pcrel)
-    {
-      switch (code)
-       {
-       case BFD_RELOC_8:
-         code = BFD_RELOC_8_PCREL;
-         break;
-       case BFD_RELOC_16:
-         code = BFD_RELOC_16_PCREL;
-         break;
-       case BFD_RELOC_32:
-         code = BFD_RELOC_32_PCREL;
-         break;
-       case BFD_RELOC_64:
-         code = BFD_RELOC_64_PCREL;
-         break;
-       case BFD_RELOC_8_PCREL:
-       case BFD_RELOC_16_PCREL:
-       case BFD_RELOC_32_PCREL:
-       case BFD_RELOC_64_PCREL:
-       case BFD_RELOC_16_PCREL_S2:
-       case BFD_RELOC_PCREL_HI16_S:
-       case BFD_RELOC_PCREL_LO16:
-         break;
-       default:
-         as_bad_where (fixp->fx_file, fixp->fx_line,
-                       _("Cannot make %s relocation PC relative"),
-                       bfd_get_reloc_code_name (code));
-       }
-    }
 
-  /* To support a PC relative reloc when generating embedded PIC code
-     for ECOFF, we use a Cygnus extension.  We check for that here to
-     make sure that we don't let such a reloc escape normally.  */
+  /* To support a PC relative reloc, we used a Cygnus extension.
+     We check for that here to make sure that we don't let such a
+     reloc escape normally.  (FIXME: This was formerly used by
+     embedded-PIC support, but is now used by branch handling in
+     general.  That probably should be fixed.)  */
   if ((OUTPUT_FLAVOR == bfd_target_ecoff_flavour
        || OUTPUT_FLAVOR == bfd_target_elf_flavour)
-      && code == BFD_RELOC_16_PCREL_S2
-      && mips_pic != EMBEDDED_PIC)
+      && code == BFD_RELOC_16_PCREL_S2)
     reloc->howto = NULL;
   else
     reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
@@ -13556,9 +12874,6 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch)
 void
 md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
 {
-  int old, new;
-  char *fixptr;
-
   if (RELAX_BRANCH_P (fragp->fr_subtype))
     {
       bfd_byte *buf;
@@ -13858,17 +13173,57 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
     }
   else
     {
-      if (fragp->fr_opcode == NULL)
-       return;
+      int first, second;
+      fixS *fixp;
+
+      first = RELAX_FIRST (fragp->fr_subtype);
+      second = RELAX_SECOND (fragp->fr_subtype);
+      fixp = (fixS *) fragp->fr_opcode;
+
+      /* Possibly emit a warning if we've chosen the longer option.  */
+      if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
+         == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
+       {
+         const char *msg = macro_warning (fragp->fr_subtype);
+         if (msg != 0)
+           as_warn_where (fragp->fr_file, fragp->fr_line, msg);
+       }
+
+      /* Go through all the fixups for the first sequence.  Disable them
+        (by marking them as done) if we're going to use the second
+        sequence instead.  */
+      while (fixp
+            && fixp->fx_frag == fragp
+            && fixp->fx_where < fragp->fr_fix - second)
+       {
+         if (fragp->fr_subtype & RELAX_USE_SECOND)
+           fixp->fx_done = 1;
+         fixp = fixp->fx_next;
+       }
 
-      old = RELAX_OLD (fragp->fr_subtype);
-      new = RELAX_NEW (fragp->fr_subtype);
-      fixptr = fragp->fr_literal + fragp->fr_fix;
+      /* Go through the fixups for the second sequence.  Disable them if
+        we're going to use the first sequence, otherwise adjust their
+        addresses to account for the relaxation.  */
+      while (fixp && fixp->fx_frag == fragp)
+       {
+         if (fragp->fr_subtype & RELAX_USE_SECOND)
+           fixp->fx_where -= first;
+         else
+           fixp->fx_done = 1;
+         fixp = fixp->fx_next;
+       }
 
-      if (new > 0)
-       memmove (fixptr - old, fixptr, new);
+      /* Now modify the frag contents.  */
+      if (fragp->fr_subtype & RELAX_USE_SECOND)
+       {
+         char *start;
 
-      fragp->fr_fix += new - old;
+         start = fragp->fr_literal + fragp->fr_fix - first - second;
+         memmove (start, start + first, second);
+         fragp->fr_fix -= first;
+       }
+      else
+       fragp->fr_fix -= second;
     }
 }
 
@@ -14642,7 +13997,6 @@ md_show_usage (FILE *stream)
 
   fprintf (stream, _("\
 MIPS options:\n\
--membedded-pic         generate embedded position independent code\n\
 -EB                    generate big endian output\n\
 -EL                    generate little endian output\n\
 -g, -g2                        do not remove unneeded NOPs or swap branches\n\
@@ -14684,6 +14038,7 @@ MIPS options:\n\
 -mips16                        generate mips16 instructions\n\
 -no-mips16             do not generate mips16 instructions\n"));
   fprintf (stream, _("\
+-mfix-vr4120           work around certain VR4120 errata\n\
 -mgp32                 use 32-bit GPRs, regardless of the chosen ISA\n\
 -mfp32                 use 32-bit FPRs, regardless of the chosen ISA\n\
 -O0                    remove unneeded NOPs, do not swap branches\n\
@@ -14730,3 +14085,12 @@ mips_dwarf2_format (void)
   else
     return dwarf2_format_32bit;
 }
+
+int
+mips_dwarf2_addr_size (void)
+{
+  if (mips_abi == N64_ABI)
+    return 8;
+  else
+    return 4;
+}
This page took 0.116896 seconds and 4 git commands to generate.