* config/tc-mips.c (macro): One more use of load_delay_nop.
[platform/upstream/binutils.git] / gas / config / tc-mips.c
index 42efce3..2239f08 100644 (file)
@@ -346,7 +346,6 @@ static int mips_32bitmode = 0;
    || mips_opts.arch == CPU_R10000                    \
    || mips_opts.arch == CPU_R12000                    \
    || mips_opts.arch == CPU_RM7000                    \
-   || mips_opts.arch == CPU_SB1                       \
    || mips_opts.arch == CPU_VR5500                    \
    )
 
@@ -357,8 +356,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
@@ -374,9 +371,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
@@ -622,7 +616,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
@@ -1863,11 +1857,11 @@ append_insn (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;
@@ -2841,7 +2835,7 @@ 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;
@@ -3789,6 +3783,13 @@ load_register (int reg, expressionS *ep, int dbl)
     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
@@ -3922,7 +3923,7 @@ load_address (int reg, expressionS *ep, int *used_at)
          ep->X_add_number = 0;
          macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
                       BFD_RELOC_MIPS_GOT16, mips_gp_register);
-         macro_build (NULL, "nop", "");
+         load_delay_nop ();
          relax_start (ep->X_add_symbol);
          relax_switch ();
          macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
@@ -4007,7 +4008,7 @@ load_address (int reg, expressionS *ep, int *used_at)
            }
          macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
                       BFD_RELOC_MIPS_GOT16, mips_gp_register);
-         macro_build (NULL, "nop", "");
+         load_delay_nop ();
          macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
                       BFD_RELOC_LO16);
          relax_end ();
@@ -4044,8 +4045,8 @@ move_register (int dest, int source)
 }
 
 /* Emit an SVR4 PIC sequence to load address LOCAL into DEST, where
-   LOCAL is the sum of a symbol and a 16-bit displacement.  The two
-   alternatives are:
+   LOCAL is the sum of a symbol and a 16-bit or 32-bit displacement.
+   The two alternatives are:
 
    Global symbol               Local sybmol
    -------------               ------------
@@ -4054,7 +4055,8 @@ move_register (int dest, int source)
    addiu DEST,DEST,OFFSET      addiu DEST,DEST,%lo(SYMBOL + OFFSET)
 
    load_got_offset emits the first instruction and add_got_offset
-   emits the second.  */
+   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)
@@ -4091,6 +4093,32 @@ add_got_offset (int dest, expressionS *local)
   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);
+}
+
 /*
  *                     Build macros
  *   This routine implements the seemingly endless macro or synthesized
@@ -4674,14 +4702,13 @@ macro (struct mips_cl_insn *ip)
          macro_build (NULL, "break", "c", 7);
        }
       expr1.X_add_number = -1;
-      macro_build (&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 (&expr1, "bne", "s,t,p", treg, AT);
       if (dbl)
        {
          expr1.X_add_number = 1;
-         macro_build (&expr1, "daddiu", "t,r,j", AT, 0, BFD_RELOC_LO16);
+         load_register (AT, &expr1, dbl);
          macro_build (NULL, "dsll32", "d,w,<", AT, AT, 31);
        }
       else
@@ -5043,12 +5070,12 @@ macro (struct mips_cl_insn *ip)
                  /* We're going to put in an addu instruction using
                     tempreg, so we may as well insert the nop right
                     now.  */
-                 macro_build (NULL, "nop", "");
+                 load_delay_nop ();
                }
              relax_switch ();
              macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                           tempreg, BFD_RELOC_MIPS_GOT16, mips_gp_register);
-             macro_build (NULL, "nop", "");
+             load_delay_nop ();
              macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                           tempreg, tempreg, BFD_RELOC_LO16);
              relax_end ();
@@ -5060,7 +5087,7 @@ macro (struct mips_cl_insn *ip)
                   && offset_expr.X_add_number < 0x8000)
            {
              load_got_offset (tempreg, &offset_expr);
-             macro_build (NULL, "nop", "");
+             load_delay_nop ();
              add_got_offset (tempreg, &offset_expr);
            }
          else
@@ -5069,6 +5096,7 @@ macro (struct mips_cl_insn *ip)
              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
@@ -5078,23 +5106,13 @@ macro (struct mips_cl_insn *ip)
                 not using a base register.  */
              if (breg == treg)
                {
-                 macro_build (NULL, "nop", "");
+                 load_delay_nop ();
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
                  breg = 0;
                  tempreg = treg;
                }
-
-             /* 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 (&expr1, AT);
-             mips_optimize = hold_mips_optimize;
-
-             add_got_offset (AT, &offset_expr);
-             macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-                          tempreg, tempreg, AT);
+             add_got_offset_hilo (tempreg, &offset_expr, AT);
              used_at = 1;
            }
        }
@@ -5162,9 +5180,7 @@ macro (struct mips_cl_insn *ip)
                      add_breg_early = 1;
                    }
 
-                 macro_build_lui (&expr1, AT);
-                 macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
-                              AT, AT, BFD_RELOC_LO16);
+                 load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               dreg, dreg, AT);
 
@@ -5273,13 +5289,13 @@ macro (struct mips_cl_insn *ip)
                  /* We're going to put in an addu instruction using
                     tempreg, so we may as well insert the nop right
                     now.  */
-                 macro_build (NULL, "nop", "");
+                 load_delay_nop ();
                }
            }
          else if (expr1.X_add_number >= -0x8000
                   && expr1.X_add_number < 0x8000)
            {
-             macro_build (NULL, "nop", "");
+             load_delay_nop ();
              macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
                           tempreg, tempreg, BFD_RELOC_LO16);
            }
@@ -5299,21 +5315,13 @@ macro (struct mips_cl_insn *ip)
              else
                {
                  assert (tempreg == AT);
-                 macro_build (NULL, "nop", "");
+                 load_delay_nop ();
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
                  dreg = treg;
                }
 
-             /* 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 (&expr1, AT);
-             mips_optimize = hold_mips_optimize;
-
-             macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
-                          AT, AT, BFD_RELOC_LO16);
+             load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
              macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dreg, dreg, AT);
 
              used_at = 1;
@@ -5334,7 +5342,7 @@ macro (struct mips_cl_insn *ip)
          if (expr1.X_add_number >= -0x8000
              && expr1.X_add_number < 0x8000)
            {
-             macro_build (NULL, "nop", "");
+             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
@@ -5350,7 +5358,7 @@ 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 (NULL, "nop", "");
+                 load_delay_nop ();
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
                  tempreg = treg;
@@ -5451,11 +5459,7 @@ macro (struct mips_cl_insn *ip)
                  add_breg_early = 1;
                }
 
-             /* Set mips_optimize around the lui instruction to avoid
-                inserting an unnecessary nop after the lw.  */
-             macro_build_lui (&expr1, AT);
-             macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
-                          AT, AT, BFD_RELOC_LO16);
+             load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
              macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dreg, dreg, AT);
 
              used_at = 1;
@@ -5640,7 +5644,7 @@ macro (struct mips_cl_insn *ip)
                  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                               PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
                               mips_gp_register);
-                 macro_build (NULL, "nop", "");
+                 load_delay_nop ();
                  relax_switch ();
                }
              else
@@ -5655,7 +5659,7 @@ macro (struct mips_cl_insn *ip)
                  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                               PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
                               PIC_CALL_REG);
-                 macro_build (NULL, "nop", "");
+                 load_delay_nop ();
                  relax_switch ();
                  if (gpdelay)
                    macro_build (NULL, "nop", "");
@@ -5663,7 +5667,7 @@ macro (struct mips_cl_insn *ip)
              macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                           PIC_CALL_REG, BFD_RELOC_MIPS_GOT16,
                           mips_gp_register);
-             macro_build (NULL, "nop", "");
+             load_delay_nop ();
              macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                           PIC_CALL_REG, PIC_CALL_REG, BFD_RELOC_LO16);
              relax_end ();
@@ -6163,7 +6167,7 @@ macro (struct mips_cl_insn *ip)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                       lw_reloc_type, mips_gp_register);
-         macro_build (NULL, "nop", "");
+         load_delay_nop ();
          relax_start (offset_expr.X_add_symbol);
          relax_switch ();
          macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg,
@@ -6213,7 +6217,7 @@ macro (struct mips_cl_insn *ip)
            macro_build (NULL, "nop", "");
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                       BFD_RELOC_MIPS_GOT16, mips_gp_register);
-         macro_build (NULL, "nop", "");
+         load_delay_nop ();
          macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg,
                       tempreg, BFD_RELOC_LO16);
          relax_end ();
@@ -6688,7 +6692,7 @@ macro (struct mips_cl_insn *ip)
              || expr1.X_add_number >= 0x8000 - 4)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          load_got_offset (AT, &offset_expr);
-         macro_build (NULL, "nop", "");
+         load_delay_nop ();
          if (breg != 0)
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
 
@@ -6747,7 +6751,7 @@ macro (struct mips_cl_insn *ip)
                       AT, AT, mips_gp_register);
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                       AT, BFD_RELOC_MIPS_GOT_LO16, AT);
-         macro_build (NULL, "nop", "");
+         load_delay_nop ();
          if (breg != 0)
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
          /* Itbl support may require additional care here.  */
@@ -6771,7 +6775,7 @@ macro (struct mips_cl_insn *ip)
            macro_build (NULL, "nop", "");
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
                       BFD_RELOC_MIPS_GOT16, mips_gp_register);
-         macro_build (NULL, "nop", "");
+         load_delay_nop ();
          if (breg != 0)
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
          /* Itbl support may require additional care here.  */
@@ -7550,8 +7554,7 @@ macro2 (struct mips_cl_insn *ip)
       if (treg == tempreg)
         return;
       /* Protect second load's delay slot.  */
-      if (!gpr_interlocks)
-       macro_build (NULL, "nop", "");
+      load_delay_nop ();
       move_register (treg, tempreg);
       break;
 
@@ -10251,10 +10254,10 @@ 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)
@@ -10496,12 +10499,12 @@ md_parse_option (int c, char *arg)
       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:
@@ -14370,6 +14373,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\
@@ -14416,3 +14420,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;
+}