* config/tc-mips.c (macro): One more use of load_delay_nop.
[platform/upstream/binutils.git] / gas / config / tc-mips.c
index 201eb61..2239f08 100644 (file)
@@ -325,15 +325,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 +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
@@ -359,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
@@ -607,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
@@ -1848,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;
@@ -2826,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;
@@ -3774,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
@@ -3907,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,
@@ -3992,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 ();
@@ -4029,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
    -------------               ------------
@@ -4039,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)
@@ -4076,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
@@ -4659,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
@@ -5028,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 ();
@@ -5045,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
@@ -5054,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
@@ -5063,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;
            }
        }
@@ -5147,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);
 
@@ -5258,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);
            }
@@ -5284,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;
@@ -5319,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
@@ -5335,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;
@@ -5436,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;
@@ -5625,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
@@ -5640,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", "");
@@ -5648,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 ();
@@ -6148,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,
@@ -6198,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 ();
@@ -6673,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);
 
@@ -6732,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.  */
@@ -6756,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.  */
@@ -7535,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;
 
@@ -10236,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)
@@ -10481,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:
@@ -14355,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\
@@ -14401,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;
+}