* elf32-m32c.c (ELF_MAXPAGESIZE): Change page size to 256 bytes.
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index ff2ffc6f9a2843d6deb07be753d0d2d987b1a72f..145f8b62ea41a2bbd366c70dab3072b08af4634c 100644 (file)
@@ -1,6 +1,7 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
    Contributed by the OSF and Ralph Campbell.
    Written by Keith Knowles and Ralph Campbell, working independently.
    Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus
@@ -751,7 +752,8 @@ static const unsigned int mips16_to_32_reg_map[] =
 
 /* Classifies the kind of instructions we're interested in when
    implementing -mfix-vr4120.  */
-enum fix_vr4120_class {
+enum fix_vr4120_class
+{
   FIX_VR4120_MACC,
   FIX_VR4120_DMACC,
   FIX_VR4120_MULT,
@@ -761,6 +763,15 @@ enum fix_vr4120_class {
   NUM_FIX_VR4120_CLASSES
 };
 
+/* ...likewise -mfix-loongson2f-jump.  */
+static bfd_boolean mips_fix_loongson2f_jump;
+
+/* ...likewise -mfix-loongson2f-nop.  */
+static bfd_boolean mips_fix_loongson2f_nop;
+
+/* True if -mfix-loongson2f-nop or -mfix-loongson2f-jump passed.  */
+static bfd_boolean mips_fix_loongson2f;
+
 /* Given two FIX_VR4120_* values X and Y, bit Y of element X is set if
    there must be at least one other instruction between an instruction
    of type X and an instruction of type Y.  */
@@ -1048,10 +1059,11 @@ static struct {
 enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
 
 static void append_insn
-  (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type *r);
+  (struct mips_cl_insn *, expressionS *, bfd_reloc_code_real_type *);
 static void mips_no_prev_insn (void);
+static void macro_build (expressionS *, const char *, const char *, ...);
 static void mips16_macro_build
-  (expressionS *, const char *, const char *, va_list);
+  (expressionS *, const char *, const char *, va_list *);
 static void load_register (int, expressionS *, int);
 static void macro_start (void);
 static void macro_end (void);
@@ -1805,11 +1817,10 @@ reg_lookup (char **s, unsigned int types, unsigned int *regnop)
 }
 
 /* Return TRUE if opcode MO is valid on the currently selected ISA and
-   architecture.  If EXPANSIONP is TRUE then this check is done while
-   expanding a macro.  Use is_opcode_valid_16 for MIPS16 opcodes.  */
+   architecture.  Use is_opcode_valid_16 for MIPS16 opcodes.  */
 
 static bfd_boolean
-is_opcode_valid (const struct mips_opcode *mo, bfd_boolean expansionp)
+is_opcode_valid (const struct mips_opcode *mo)
 {
   int isa = mips_opts.isa;
   int fp_s, fp_d;
@@ -1829,11 +1840,6 @@ is_opcode_valid (const struct mips_opcode *mo, bfd_boolean expansionp)
   if (mips_opts.ase_smartmips)
     isa |= INSN_SMARTMIPS;
 
-  /* For user code we don't check for mips_opts.mips16 since we want
-     to allow jalx if -mips16 was specified on the command line.  */
-  if (expansionp ? mips_opts.mips16 : file_ase_mips16)
-    isa |= INSN_MIPS16;
-
   /* Don't accept instructions based on the ISA if the CPU does not implement
      all the coprocessor insns. */
   if (NO_ISA_COP (mips_opts.arch)
@@ -1918,6 +1924,8 @@ md_begin (void)
              if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
                {
                  create_insn (&nop_insn, mips_opcodes + i);
+                 if (mips_fix_loongson2f_nop)
+                   nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
                  nop_insn.fixed_p = 1;
                }
            }
@@ -2722,7 +2730,9 @@ nops_for_insn_or_target (const struct mips_cl_insn *hist,
       if (tmp_nops > nops)
        nops = tmp_nops;
     }
-  else if (mips_opts.mips16 && (insn->insn_mo->pinfo & MIPS16_INSN_BRANCH))
+  else if (mips_opts.mips16
+          && (insn->insn_mo->pinfo & (MIPS16_INSN_UNCOND_BRANCH
+                                      | MIPS16_INSN_COND_BRANCH)))
     {
       tmp_nops = nops_for_sequence (1, hist, insn);
       if (tmp_nops > nops)
@@ -2731,6 +2741,54 @@ nops_for_insn_or_target (const struct mips_cl_insn *hist,
   return nops;
 }
 
+/* Fix NOP issue: Replace nops by "or at,at,zero".  */
+
+static void
+fix_loongson2f_nop (struct mips_cl_insn * ip)
+{
+  if (strcmp (ip->insn_mo->name, "nop") == 0)
+    ip->insn_opcode = LOONGSON2F_NOP_INSN;
+}
+
+/* Fix Jump Issue: Eliminate instruction fetch from outside 256M region
+                   jr target pc &= 'hffff_ffff_cfff_ffff.  */
+
+static void
+fix_loongson2f_jump (struct mips_cl_insn * ip)
+{
+  if (strcmp (ip->insn_mo->name, "j") == 0
+      || strcmp (ip->insn_mo->name, "jr") == 0
+      || strcmp (ip->insn_mo->name, "jalr") == 0)
+    {
+      int sreg;
+      expressionS ep;
+
+      if (! mips_opts.at)
+        return;
+
+      sreg = EXTRACT_OPERAND (RS, *ip);
+      if (sreg == ZERO || sreg == KT0 || sreg == KT1 || sreg == ATREG)
+        return;
+
+      ep.X_op = O_constant;
+      ep.X_add_number = 0xcfff0000;
+      macro_build (&ep, "lui", "t,u", ATREG, BFD_RELOC_HI16);
+      ep.X_add_number = 0xffff;
+      macro_build (&ep, "ori", "t,r,i", ATREG, ATREG, BFD_RELOC_LO16);
+      macro_build (NULL, "and", "d,v,t", sreg, sreg, ATREG);
+    }
+}
+
+static void
+fix_loongson2f (struct mips_cl_insn * ip)
+{
+  if (mips_fix_loongson2f_nop)
+    fix_loongson2f_nop (ip);
+
+  if (mips_fix_loongson2f_jump)
+    fix_loongson2f_jump (ip);
+}
+
 /* Output an instruction.  IP is the instruction information.
    ADDRESS_EXPR is an operand of the instruction to be used with
    RELOC_TYPE.  */
@@ -2744,6 +2802,9 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   bfd_boolean relaxed_branch = FALSE;
   segment_info_type *si = seg_info (now_seg);
 
+  if (mips_fix_loongson2f)
+    fix_loongson2f (ip);
+
   /* Mark instruction labels in mips16 mode.  */
   mips16_mark_labels ();
 
@@ -3555,7 +3616,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
 
   if (mips_opts.mips16)
     {
-      mips16_macro_build (ep, name, fmt, args);
+      mips16_macro_build (ep, name, fmt, &args);
       va_end (args);
       return;
     }
@@ -3573,7 +3634,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
         macros will never generate MDMX, MIPS-3D, or MT instructions.  */
       if (strcmp (fmt, mo->args) == 0
          && mo->pinfo != INSN_MACRO
-         && is_opcode_valid (mo, TRUE))
+         && is_opcode_valid (mo))
        break;
 
       ++mo;
@@ -3781,7 +3842,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
 
 static void
 mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
-                   va_list args)
+                   va_list *args)
 {
   struct mips_opcode *mo;
   struct mips_cl_insn insn;
@@ -3817,20 +3878,20 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
 
        case 'y':
        case 'w':
-         MIPS16_INSERT_OPERAND (RY, insn, va_arg (args, int));
+         MIPS16_INSERT_OPERAND (RY, insn, va_arg (*args, int));
          continue;
 
        case 'x':
        case 'v':
-         MIPS16_INSERT_OPERAND (RX, insn, va_arg (args, int));
+         MIPS16_INSERT_OPERAND (RX, insn, va_arg (*args, int));
          continue;
 
        case 'z':
-         MIPS16_INSERT_OPERAND (RZ, insn, va_arg (args, int));
+         MIPS16_INSERT_OPERAND (RZ, insn, va_arg (*args, int));
          continue;
 
        case 'Z':
-         MIPS16_INSERT_OPERAND (MOVE32Z, insn, va_arg (args, int));
+         MIPS16_INSERT_OPERAND (MOVE32Z, insn, va_arg (*args, int));
          continue;
 
        case '0':
@@ -3840,14 +3901,14 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
          continue;
 
        case 'X':
-         MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (args, int));
+         MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (*args, int));
          continue;
 
        case 'Y':
          {
            int regno;
 
-           regno = va_arg (args, int);
+           regno = va_arg (*args, int);
            regno = ((regno & 7) << 2) | ((regno & 0x18) >> 3);
            MIPS16_INSERT_OPERAND (REG32R, insn, regno);
          }
@@ -3886,7 +3947,7 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
          continue;
 
        case '6':
-         MIPS16_INSERT_OPERAND (IMM6, insn, va_arg (args, int));
+         MIPS16_INSERT_OPERAND (IMM6, insn, va_arg (*args, int));
          continue;
        }
 
@@ -6158,6 +6219,8 @@ macro (struct mips_cl_insn *ip)
                      /* Quiet this warning.  */
                      mips_cprestore_valid = 1;
                    }
+                 if (mips_opts.noreorder)
+                   macro_build (NULL, "nop", "");
                  expr1.X_add_number = mips_cprestore_offset;
                  macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
                                                mips_gp_register,
@@ -8711,7 +8774,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
 
       gas_assert (strcmp (insn->name, str) == 0);
 
-      ok = is_opcode_valid (insn, FALSE);
+      ok = is_opcode_valid (insn);
       if (! ok)
        {
          if (insn + 1 < &mips_opcodes[NUMOPCODES]
@@ -9890,9 +9953,7 @@ do_msbd:
                    /* Set the argument to the current address in the
                       section.  */
                    offset_expr.X_op = O_symbol;
-                   offset_expr.X_add_symbol =
-                     symbol_new ("L0\001", now_seg,
-                                 (valueT) frag_now_fix (), frag_now);
+                   offset_expr.X_add_symbol = symbol_temp_new_now ();
                    offset_expr.X_add_number = 0;
 
                    /* Put the floating point number into the section.  */
@@ -11216,6 +11277,10 @@ enum options
     OPTION_MNO_7000_HILO_FIX, 
     OPTION_FIX_24K,
     OPTION_NO_FIX_24K,
+    OPTION_FIX_LOONGSON2F_JUMP,
+    OPTION_NO_FIX_LOONGSON2F_JUMP,
+    OPTION_FIX_LOONGSON2F_NOP,
+    OPTION_NO_FIX_LOONGSON2F_NOP,
     OPTION_FIX_VR4120,
     OPTION_NO_FIX_VR4120,
     OPTION_FIX_VR4130,
@@ -11304,6 +11369,10 @@ struct option md_longopts[] =
   {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
   {"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
   {"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
+  {"mfix-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP},
+  {"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP},
+  {"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
+  {"mno-fix-loongson2f-nop", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_NOP},
   {"mfix-vr4120",    no_argument, NULL, OPTION_FIX_VR4120},
   {"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
   {"mfix-vr4130",    no_argument, NULL, OPTION_FIX_VR4130},
@@ -11571,6 +11640,22 @@ md_parse_option (int c, char *arg)
       mips_fix_24k = 0;
       break;
 
+    case OPTION_FIX_LOONGSON2F_JUMP:
+      mips_fix_loongson2f_jump = TRUE;
+      break;
+
+    case OPTION_NO_FIX_LOONGSON2F_JUMP:
+      mips_fix_loongson2f_jump = FALSE;
+      break;
+
+    case OPTION_FIX_LOONGSON2F_NOP:
+      mips_fix_loongson2f_nop = TRUE;
+      break;
+
+    case OPTION_NO_FIX_LOONGSON2F_NOP:
+      mips_fix_loongson2f_nop = FALSE;
+      break;
+
     case OPTION_FIX_VR4120:
       mips_fix_vr4120 = 1;
       break;
@@ -11785,6 +11870,8 @@ md_parse_option (int c, char *arg)
       return 0;
     }
 
+    mips_fix_loongson2f = mips_fix_loongson2f_nop || mips_fix_loongson2f_jump;
+
   return 1;
 }
 \f
@@ -12147,7 +12234,7 @@ mips_frob_file (void)
            hi_pos = pos;
 
          if ((*pos)->fx_r_type == looking_for_rtype
-             && (*pos)->fx_addsy == l->fixp->fx_addsy
+             && symbol_same_p ((*pos)->fx_addsy, l->fixp->fx_addsy)
              && (*pos)->fx_offset >= l->fixp->fx_offset
              && (lo_pos == NULL
                  || (*pos)->fx_offset < (*lo_pos)->fx_offset
@@ -12610,6 +12697,8 @@ s_change_section (int ignore ATTRIBUTE_UNUSED)
     section_alignment = get_absolute_expression ();
   else
     section_alignment = 0;
+  /* FIXME: really ignore?  */
+  (void) section_alignment;
 
   section_name = xstrdup (section_name);
 
@@ -14790,6 +14879,8 @@ void
 mips_handle_align (fragS *fragp)
 {
   char *p;
+  int bytes, size, excess;
+  valueT opcode;
 
   if (fragp->fr_type != rs_align_code)
     return;
@@ -14797,17 +14888,28 @@ mips_handle_align (fragS *fragp)
   p = fragp->fr_literal + fragp->fr_fix;
   if (*p)
     {
-      int bytes;
+      opcode = mips16_nop_insn.insn_opcode;
+      size = 2;
+    }
+  else
+    {
+      opcode = nop_insn.insn_opcode;
+      size = 4;
+    }
 
-      bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
-      if (bytes & 1)
-       {
-         *p++ = 0;
-         fragp->fr_fix++;
-       }
-      md_number_to_chars (p, mips16_nop_insn.insn_opcode, 2);
-      fragp->fr_var = 2;
+  bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
+  excess = bytes % size;
+  if (excess != 0)
+    {
+      /* If we're not inserting a whole number of instructions,
+        pad the end of the fixed part of the frag with zeros.  */
+      memset (p, 0, excess);
+      p += excess;
+      fragp->fr_fix += excess;
     }
+
+  md_number_to_chars (p, opcode, size);
+  fragp->fr_var = size;
 }
 
 static void
@@ -14979,12 +15081,9 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
     {
       segT saved_seg = now_seg;
       subsegT saved_subseg = now_subseg;
-      valueT dot;
       expressionS exp;
       char *fragp;
 
-      dot = frag_now_fix ();
-
 #ifdef md_flush_pending_output
       md_flush_pending_output ();
 #endif
@@ -15047,8 +15146,6 @@ s_mips_ent (int aent)
 
       cur_proc_ptr->func_sym = symbolP;
 
-      symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
-
       ++numprocs;
 
       if (debug_type == DEBUG_STABS)
@@ -15056,6 +15153,8 @@ s_mips_ent (int aent)
                                 S_GET_NAME (symbolP));
     }
 
+  symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
+
   demand_empty_rest_of_line ();
 }
 
@@ -15519,6 +15618,8 @@ MIPS options:\n\
 -mmt                   generate MT instructions\n\
 -mno-mt                        do not generate MT instructions\n"));
   fprintf (stream, _("\
+-mfix-loongson2f-jump  work around Loongson2F JUMP instructions\n\
+-mfix-loongson2f-nop   work around Loongson2F NOP errata\n\
 -mfix-vr4120           work around certain VR4120 errata\n\
 -mfix-vr4130           work around VR4130 mflo/mfhi errata\n\
 -mfix-24k              insert a nop after ERET and DERET instructions\n\
@@ -15565,20 +15666,16 @@ MIPS options:\n\
 #endif
 }
 
+#ifdef TE_IRIX
 enum dwarf2_format
 mips_dwarf2_format (asection *sec ATTRIBUTE_UNUSED)
 {
   if (HAVE_64BIT_SYMBOLS)
-    {
-#ifdef TE_IRIX
-      return dwarf2_format_64bit_irix;
-#else
-      return dwarf2_format_64bit;
-#endif
-    }
+    return dwarf2_format_64bit_irix;
   else
     return dwarf2_format_32bit;
 }
+#endif
 
 int
 mips_dwarf2_addr_size (void)
This page took 0.03378 seconds and 4 git commands to generate.