Fix for PR6697:
authorKen Raeburn <raeburn@cygnus>
Tue, 11 Apr 1995 01:29:49 +0000 (01:29 +0000)
committerKen Raeburn <raeburn@cygnus>
Tue, 11 Apr 1995 01:29:49 +0000 (01:29 +0000)
(nopic_need_relax): New static function, split out from
md_estimate_size_before_relax.
(md_estimate_size_before_relax): Call it.
(load_address, macro): In NO_PIC branches, if nopic_need_relax returns nonzero,
don't attempt GP optimization.

gas/config/tc-mips.c

index f3677ec3a60aa4363a968cbaf34557a41907acfc..4fb2c0aeaf2891c1d5de18e781b4b3502473303c 100644 (file)
@@ -168,6 +168,19 @@ static int g_switch_seen = 0;
 #define N_RMASK 0xc4
 #define N_VFP   0xd4
 
+/* If we can determine in advance that GP optimization won't be
+   possible, we can skip the relaxation stuff that tries to produce
+   GP-relative references.  This makes delay slot optimization work
+   better.
+
+   This function can only provide a guess, but it seems to work for
+   gcc output.  If it guesses wrong, the only loss should be in
+   efficiency; it shouldn't introduce any bugs.
+
+   I don't know if a fix is needed for the SVR4_PIC mode.  I've only
+   fixed it for the non-PIC mode.  KR 95/04/07  */
+static int nopic_need_relax PARAMS ((symbolS *));
+
 /* handle of the OPCODE hash table */
 static struct hash_control *op_hash = NULL;
 
@@ -361,7 +374,7 @@ static void macro_build_lui PARAMS ((char *place, int *counter,
 static void set_at PARAMS ((int *counter, int reg, int unsignedp));
 static void check_absolute_expr PARAMS ((struct mips_cl_insn * ip,
                                         expressionS *));
-static void load_register PARAMS ((int *counter, int reg, expressionS * ep));
+static void load_register PARAMS ((int *, int, expressionS *, int));
 static void load_address PARAMS ((int *counter, int reg, expressionS *ep));
 static void macro PARAMS ((struct mips_cl_insn * ip));
 #ifdef LOSING_COMPILER
@@ -580,6 +593,19 @@ md_begin ()
          if (mips_4650 == -1)
            mips_4650 = 1;
        }
+      else if (strcmp (cpu, "r8000") == 0
+              || strcmp (cpu, "mips4") == 0)
+       {
+         mips_isa = 4;
+         if (mips_cpu == -1)
+           mips_cpu = 8000;
+       }
+      else if (strcmp (cpu, "r10000") == 0)
+       {
+         mips_isa = 4;
+         if (mips_cpu == -1)
+           mips_cpu = 10000;
+       }
       else
        {
          mips_isa = 1;
@@ -608,6 +634,9 @@ md_begin ()
     case 3:
       ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 4000);
       break;
+    case 4:
+      ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 8000);
+      break;
     }
   if (! ok)
     as_warn ("Could not set architecture and machine");
@@ -831,9 +860,10 @@ append_insn (place, ip, address_expr, reloc_type)
 
       /* The previous insn might require a delay slot, depending upon
         the contents of the current insn.  */
-      if ((prev_pinfo & INSN_LOAD_COPROC_DELAY)
-         || (mips_isa < 2
-             && (prev_pinfo & INSN_LOAD_MEMORY_DELAY)))
+      if (mips_isa < 4
+         && ((prev_pinfo & INSN_LOAD_COPROC_DELAY)
+             || (mips_isa < 2
+                 && (prev_pinfo & INSN_LOAD_MEMORY_DELAY))))
        {
          /* A load from a coprocessor or from memory.  All load
             delays delay the use of general register rt for one
@@ -847,9 +877,10 @@ append_insn (place, ip, address_expr, reloc_type)
                                0))
            ++nops;
        }
-      else if ((prev_pinfo & INSN_COPROC_MOVE_DELAY)
-              || (mips_isa < 2
-                  && (prev_pinfo & INSN_COPROC_MEMORY_DELAY)))
+      else if (mips_isa < 4
+              && ((prev_pinfo & INSN_COPROC_MOVE_DELAY)
+                  || (mips_isa < 2
+                      && (prev_pinfo & INSN_COPROC_MEMORY_DELAY))))
        {
          /* A generic coprocessor delay.  The previous instruction
             modified a coprocessor general or control register.  If
@@ -899,7 +930,8 @@ append_insn (place, ip, address_expr, reloc_type)
                ++nops;
            }
        }
-      else if (prev_pinfo & INSN_WRITE_COND_CODE)
+      else if (mips_isa < 4
+              && (prev_pinfo & INSN_WRITE_COND_CODE))
        {
          /* The previous instruction sets the coprocessor condition
             codes, but does not require a general coprocessor delay
@@ -940,7 +972,8 @@ append_insn (place, ip, address_expr, reloc_type)
         instruction, we must check for these cases compared to the
         instruction previous to the previous instruction.  */
       if (nops == 0
-         && (((prev_prev_insn.insn_mo->pinfo & INSN_COPROC_MOVE_DELAY)
+         && ((mips_isa < 4
+              && (prev_prev_insn.insn_mo->pinfo & INSN_COPROC_MOVE_DELAY)
               && (prev_prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE)
               && (pinfo & INSN_READ_COND_CODE))
              || ((prev_prev_insn.insn_mo->pinfo & INSN_READ_LO)
@@ -1045,6 +1078,8 @@ append_insn (place, ip, address_expr, reloc_type)
     mips_cprmask[1] |= 1 << ((ip->insn_opcode >> OP_SH_FS) & OP_MASK_FS);
   if ((pinfo & (INSN_WRITE_FPR_T | INSN_READ_FPR_T)) != 0)
     mips_cprmask[1] |= 1 << ((ip->insn_opcode >> OP_SH_FT) & OP_MASK_FT);
+  if ((pinfo & INSN_READ_FPR_R) != 0)
+    mips_cprmask[1] |= 1 << ((ip->insn_opcode >> OP_SH_FR) & OP_MASK_FR);
   if (pinfo & INSN_COP)
     {
       /* We don't keep enough information to sort these cases out.  */
@@ -1109,14 +1144,16 @@ append_insn (place, ip, address_expr, reloc_type)
                   bc1t LABEL
                 we can not swap, and I don't feel like handling that
                 case.  */
-             || (pinfo & INSN_READ_COND_CODE)
+             || (mips_isa < 4
+                 && (pinfo & INSN_READ_COND_CODE))
              /* We can not swap with an instruction that requires a
                 delay slot, becase the target of the branch might
                 interfere with that instruction.  */
-             || (prev_pinfo
-                 & (INSN_LOAD_COPROC_DELAY
-                    | INSN_COPROC_MOVE_DELAY
-                    | INSN_WRITE_COND_CODE))
+             || (mips_isa < 4
+                 && (prev_pinfo
+                     & (INSN_LOAD_COPROC_DELAY
+                        | INSN_COPROC_MOVE_DELAY
+                        | INSN_WRITE_COND_CODE)))
              || (! mips_4650
                  && (prev_pinfo
                      & (INSN_READ_LO
@@ -1183,10 +1220,11 @@ append_insn (place, ip, address_expr, reloc_type)
              /* If the previous previous instruction has a load
                 delay, and sets a register that the branch reads, we
                 can not swap.  */
-             || (((prev_prev_insn.insn_mo->pinfo & INSN_LOAD_COPROC_DELAY)
-                  || (mips_isa < 2
-                      && (prev_prev_insn.insn_mo->pinfo
-                          & INSN_LOAD_MEMORY_DELAY)))
+             || (mips_isa < 4
+                 && ((prev_prev_insn.insn_mo->pinfo & INSN_LOAD_COPROC_DELAY)
+                     || (mips_isa < 2
+                         && (prev_prev_insn.insn_mo->pinfo
+                             & INSN_LOAD_MEMORY_DELAY)))
                  && insn_uses_reg (ip,
                                    ((prev_prev_insn.insn_opcode >> OP_SH_RT)
                                     & OP_MASK_RT),
@@ -1301,10 +1339,11 @@ mips_emit_delays ()
       int nop;
 
       nop = 0;
-      if ((prev_insn.insn_mo->pinfo
-          & (INSN_LOAD_COPROC_DELAY
-             | INSN_COPROC_MOVE_DELAY
-             | INSN_WRITE_COND_CODE))
+      if ((mips_isa < 4
+          && (prev_insn.insn_mo->pinfo
+              & (INSN_LOAD_COPROC_DELAY
+                 | INSN_COPROC_MOVE_DELAY
+                 | INSN_WRITE_COND_CODE)))
          || (! mips_4650
              && (prev_insn.insn_mo->pinfo
                  & (INSN_READ_LO
@@ -1315,13 +1354,15 @@ mips_emit_delays ()
                     | INSN_COPROC_MEMORY_DELAY))))
        {
          nop = 1;
-         if ((prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE)
+         if ((mips_isa < 4
+              && (prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE))
              || (! mips_4650
                  && ((prev_insn.insn_mo->pinfo & INSN_READ_HI)
                      || (prev_insn.insn_mo->pinfo & INSN_READ_LO))))
            emit_nop ();
        }
-      else if ((prev_prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE)
+      else if ((mips_isa < 4
+               && (prev_prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE))
               || (! mips_4650
                   && ((prev_prev_insn.insn_mo->pinfo & INSN_READ_HI)
                       || (prev_prev_insn.insn_mo->pinfo & INSN_READ_LO))))
@@ -1605,7 +1646,7 @@ set_at (counter, reg, unsignedp)
                 "t,r,j", AT, reg, (int) BFD_RELOC_LO16);
   else
     {
-      load_register (counter, AT, &imm_expr);
+      load_register (counter, AT, &imm_expr, 0);
       macro_build ((char *) NULL, counter, NULL,
                   unsignedp ? "sltu" : "slt",
                   "d,v,t", AT, reg, AT);
@@ -1628,18 +1669,24 @@ check_absolute_expr (ip, ex)
  *  an absolute expression value into a register.
  */
 static void
-load_register (counter, reg, ep)
+load_register (counter, reg, ep, dbl)
      int *counter;
      int reg;
      expressionS *ep;
+     int dbl;
 {
-  int shift;
+  int shift, freg;
   expressionS hi32, lo32, tmp;
 
   if (ep->X_op != O_big)
     {
       assert (ep->X_op == O_constant);
-      if (ep->X_add_number >= -0x8000 && ep->X_add_number < 0x8000)
+      if (ep->X_add_number < 0x8000
+         && (ep->X_add_number >= 0
+             || (ep->X_add_number >= -0x8000
+                 && (! dbl
+                     || ! ep->X_unsigned
+                     || sizeof (ep->X_add_number) > 4))))
        {
          /* We can handle 16 bit signed values with an addiu to
             $zero.  No need to ever use daddiu here, since $zero and
@@ -1659,7 +1706,7 @@ load_register (counter, reg, ep)
       else if (((ep->X_add_number &~ (offsetT) 0x7fffffff) == 0
                || ((ep->X_add_number &~ (offsetT) 0x7fffffff)
                    == ~ (offsetT) 0x7fffffff))
-              && (mips_isa < 3
+              && (! dbl
                   || ! ep->X_unsigned
                   || sizeof (ep->X_add_number) > 4
                   || (ep->X_add_number & 0x80000000) == 0))
@@ -1721,25 +1768,42 @@ load_register (counter, reg, ep)
       hi32.X_add_number = generic_bignum[2] + (generic_bignum[3] << 16);
     }
 
-  load_register (counter, reg, &hi32);
+  if (hi32.X_add_number == 0)
+    freg = 0;
+  else
+    {
+      load_register (counter, reg, &hi32, 0);
+      freg = reg;
+    }
   if ((lo32.X_add_number & 0xffff0000) == 0)
-    macro_build ((char *) NULL, counter, NULL, "dsll32", "d,w,<", reg,
-                reg, 0);
+    {
+      if (freg != 0)
+       {
+         macro_build ((char *) NULL, counter, NULL, "dsll32", "d,w,<", reg,
+                      freg, 0);
+         freg = reg;
+       }
+    }
   else
     {
       expressionS mid16;
 
-      macro_build ((char *) NULL, counter, NULL, "dsll", "d,w,<", reg,
-                  reg, 16);
+      if (freg != 0)
+       {
+         macro_build ((char *) NULL, counter, NULL, "dsll", "d,w,<", reg,
+                      freg, 16);
+         freg = reg;
+       }
       mid16 = lo32;
       mid16.X_add_number >>= 16;
       macro_build ((char *) NULL, counter, &mid16, "ori", "t,r,i", reg,
-                  reg, (int) BFD_RELOC_LO16);
+                  freg, (int) BFD_RELOC_LO16);
       macro_build ((char *) NULL, counter, NULL, "dsll", "d,w,<", reg,
                   reg, 16);
+      freg = reg;
     }
   if ((lo32.X_add_number & 0xffff) != 0)
-    macro_build ((char *) NULL, counter, &lo32, "ori", "t,r,i", reg, reg,
+    macro_build ((char *) NULL, counter, &lo32, "ori", "t,r,i", reg, freg,
                 (int) BFD_RELOC_LO16);
 }
 
@@ -1762,7 +1826,7 @@ load_address (counter, reg, ep)
 
   if (ep->X_op == O_constant)
     {
-      load_register (counter, reg, ep);
+      load_register (counter, reg, ep, 0);
       return;
     }
 
@@ -1774,7 +1838,7 @@ load_address (counter, reg, ep)
           lui          $reg,<sym>              (BFD_RELOC_HI16_S)
           addiu        $reg,$reg,<sym>         (BFD_RELOC_LO16)
         If we have an addend, we always use the latter form.  */
-      if (ep->X_add_number != 0)
+      if (ep->X_add_number != 0 || nopic_need_relax (ep->X_add_symbol))
        p = NULL;
       else
        {
@@ -1942,7 +2006,7 @@ macro (ip)
                       (int) BFD_RELOC_LO16);
          return;
        }
-      load_register (&icnt, AT, &imm_expr);
+      load_register (&icnt, AT, &imm_expr, dbl);
       macro_build ((char *) NULL, &icnt, NULL, s2, "d,v,t", treg, sreg, AT);
       break;
 
@@ -1977,7 +2041,7 @@ macro (ip)
          return;
        }
 
-      load_register (&icnt, AT, &imm_expr);
+      load_register (&icnt, AT, &imm_expr, 0);
       macro_build ((char *) NULL, &icnt, NULL, s2, "d,v,t", treg, sreg, AT);
       break;
 
@@ -2001,7 +2065,7 @@ macro (ip)
                       0);
          return;
        }
-      load_register (&icnt, AT, &imm_expr);
+      load_register (&icnt, AT, &imm_expr, 0);
       macro_build ((char *) NULL, &icnt, &offset_expr, s, "s,t,p", sreg, AT);
       break;
 
@@ -2478,7 +2542,7 @@ macro (ip)
          return;
        }
 
-      load_register (&icnt, AT, &imm_expr);
+      load_register (&icnt, AT, &imm_expr, dbl);
       macro_build ((char *) NULL, &icnt, NULL, s, "z,s,t", sreg, AT);
       macro_build ((char *) NULL, &icnt, NULL, s2, "d", dreg);
       break;
@@ -2516,6 +2580,8 @@ macro (ip)
       macro_build ((char *) NULL, &icnt, NULL, s2, "d", dreg);
       return;
 
+    case M_DLA_AB:
+      dbl = 1;
     case M_LA_AB:
       /* Load the address of a symbol into a register.  If breg is not
         zero, we then add a base register to it.  */
@@ -2567,7 +2633,7 @@ macro (ip)
        }
 
       if (offset_expr.X_op == O_constant)
-       load_register (&icnt, tempreg, &offset_expr);
+       load_register (&icnt, tempreg, &offset_expr, dbl);
       else if (mips_pic == NO_PIC)
        {
          /* If this is a reference to an GP relative symbol, we want
@@ -2577,7 +2643,8 @@ macro (ip)
               addiu    $tempreg,$tempreg,<sym> (BFD_RELOC_LO16)
             If we have a constant, we need two instructions anyhow,
             so we may as well always use the latter form.  */
-         if (offset_expr.X_add_number != 0)
+         if (offset_expr.X_add_number != 0
+             || nopic_need_relax (offset_expr.X_add_symbol))
            p = NULL;
          else
            {
@@ -2630,7 +2697,7 @@ macro (ip)
          offset_expr.X_add_number = 0;
          frag_grow (32);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      mips_isa < 3 ? "lw" : "ld",
+                      dbl ? "ld" : "lw",
                       "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
          if (expr1.X_add_number == 0)
            {
@@ -3031,7 +3098,8 @@ macro (ip)
             With a constant we always use the latter case.  */
          if (breg == 0)
            {
-             if (offset_expr.X_add_number != 0)
+             if (offset_expr.X_add_number != 0
+                 || nopic_need_relax (offset_expr.X_add_symbol))
                p = NULL;
              else
                {
@@ -3054,7 +3122,8 @@ macro (ip)
            }
          else
            {
-             if (offset_expr.X_add_number != 0)
+             if (offset_expr.X_add_number != 0
+                 || nopic_need_relax (offset_expr.X_add_symbol))
                p = NULL;
              else
                {
@@ -3157,13 +3226,17 @@ macro (ip)
 
     case M_LI:
     case M_LI_S:
-      load_register (&icnt, treg, &imm_expr);
+      load_register (&icnt, treg, &imm_expr, 0);
+      return;
+
+    case M_DLI:
+      load_register (&icnt, treg, &imm_expr, 1);
       return;
 
     case M_LI_SS:
       if (imm_expr.X_op == O_constant)
        {
-         load_register (&icnt, AT, &imm_expr);
+         load_register (&icnt, AT, &imm_expr, 0);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                       "mtc1", "t,G", AT, treg);
          break;
@@ -3390,7 +3463,8 @@ macro (ip)
             If there is a base register, we add it to $at after the
             lui instruction.  If there is a constant, we always use
             the last case.  */
-         if (offset_expr.X_add_number != 0)
+         if (offset_expr.X_add_number != 0
+             || nopic_need_relax (offset_expr.X_add_symbol))
            {
              p = NULL;
              used_at = 1;
@@ -3638,7 +3712,7 @@ macro2 (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);
+      load_register (&icnt, AT, &imm_expr, dbl);
       macro_build ((char *) NULL, &icnt, NULL,
                   dbl ? "dmult" : "mult",
                   "s,t", sreg, AT);
@@ -3787,7 +3861,7 @@ macro2 (ip)
        }
       else
        {
-         load_register (&icnt, AT, &imm_expr);
+         load_register (&icnt, AT, &imm_expr, 0);
          macro_build ((char *) NULL, &icnt, NULL, "xor", "d,v,t", dreg,
                       sreg, AT);
          used_at = 1;
@@ -3820,7 +3894,7 @@ macro2 (ip)
        }
       else
        {
-         load_register (&icnt, AT, &imm_expr);
+         load_register (&icnt, AT, &imm_expr, 0);
          macro_build ((char *) NULL, &icnt, NULL,
                       mask == M_SGE_I ? "slt" : "sltu",
                       "d,v,t", dreg, sreg, AT);
@@ -3847,7 +3921,7 @@ macro2 (ip)
     case M_SGTU_I:
       s = "sltu";
     sgti:
-      load_register (&icnt, AT, &imm_expr);
+      load_register (&icnt, AT, &imm_expr, 0);
       macro_build ((char *) NULL, &icnt, NULL, s, "d,v,t", dreg, AT, sreg);
       break;
 
@@ -3868,7 +3942,7 @@ macro2 (ip)
     case M_SLEU_I:
       s = "sltu";
     slei:
-      load_register (&icnt, AT, &imm_expr);
+      load_register (&icnt, AT, &imm_expr, 0);
       macro_build ((char *) NULL, &icnt, NULL, s, "d,v,t", dreg, AT, sreg);
       macro_build ((char *) NULL, &icnt, &expr1, "xori", "t,r,i", dreg, dreg,
                   (int) BFD_RELOC_LO16);
@@ -3881,7 +3955,7 @@ macro2 (ip)
                       dreg, sreg, (int) BFD_RELOC_LO16);
          return;
        }
-      load_register (&icnt, AT, &imm_expr);
+      load_register (&icnt, AT, &imm_expr, 0);
       macro_build ((char *) NULL, &icnt, NULL, "slt", "d,v,t", dreg, sreg, AT);
       break;
 
@@ -3892,7 +3966,7 @@ macro2 (ip)
                       dreg, sreg, (int) BFD_RELOC_LO16);
          return;
        }
-      load_register (&icnt, AT, &imm_expr);
+      load_register (&icnt, AT, &imm_expr, 0);
       macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", dreg, sreg,
                   AT);
       break;
@@ -3945,7 +4019,7 @@ macro2 (ip)
        }
       else
        {
-         load_register (&icnt, AT, &imm_expr);
+         load_register (&icnt, AT, &imm_expr, 0);
          macro_build ((char *) NULL, &icnt, NULL, "xor", "d,v,t", dreg,
                       sreg, AT);
          used_at = 1;
@@ -3966,7 +4040,7 @@ macro2 (ip)
                       "t,r,j", dreg, sreg, (int) BFD_RELOC_LO16);
          return;
        }
-      load_register (&icnt, AT, &imm_expr);
+      load_register (&icnt, AT, &imm_expr, dbl);
       macro_build ((char *) NULL, &icnt, NULL,
                   dbl ? "dsub" : "sub",
                   "d,v,t", dreg, sreg, AT);
@@ -3983,7 +4057,7 @@ macro2 (ip)
                       "t,r,j", dreg, sreg, (int) BFD_RELOC_LO16);
          return;
        }
-      load_register (&icnt, AT, &imm_expr);
+      load_register (&icnt, AT, &imm_expr, dbl);
       macro_build ((char *) NULL, &icnt, NULL,
                   dbl ? "dsubu" : "subu",
                   "d,v,t", dreg, sreg, AT);
@@ -4007,7 +4081,7 @@ macro2 (ip)
     case M_TNE_I:
       s = "tne";
     trap:
-      load_register (&icnt, AT, &imm_expr);
+      load_register (&icnt, AT, &imm_expr, 0);
       macro_build ((char *) NULL, &icnt, NULL, s, "s,t", sreg, AT);
       break;
 
@@ -4288,6 +4362,8 @@ mips_ip (str, ip)
        insn_isa = 2;
       else if ((insn->pinfo & INSN_ISA) == INSN_ISA3)
        insn_isa = 3;
+      else if ((insn->pinfo & INSN_ISA) == INSN_ISA4)
+       insn_isa = 4;
       else
        insn_isa = 1;
 
@@ -4386,15 +4462,20 @@ mips_ip (str, ip)
              continue;
 
            case 'k':           /* cache code */
+           case 'h':           /* prefx code */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > 31)
                {
-                 as_warn ("Invalid cahce opcode (%lu)",
+                 as_warn ("Invalid value for `%s' (%lu)",
+                          ip->insn_mo->name,
                           (unsigned long) imm_expr.X_add_number);
                  imm_expr.X_add_number &= 0x1f;
                }
-             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CACHE;
+             if (*args == 'k')
+               ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CACHE;
+             else
+               ip->insn_opcode |= imm_expr.X_add_number << OP_SH_PREFX;
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
@@ -4569,6 +4650,7 @@ mips_ip (str, ip)
            case 'D':           /* floating point destination register */
            case 'S':           /* floating point source register */
            case 'T':           /* floating point target register */
+           case 'R':           /* floating point source register */
            case 'V':
            case 'W':
              s_reset = s;
@@ -4620,6 +4702,10 @@ mips_ip (str, ip)
                    case 'W':
                    case 'T':
                      ip->insn_opcode |= regno << 16;
+                     break;
+                   case 'R':
+                     ip->insn_opcode |= regno << 21;
+                     break;
                    }
                  lastregno = regno;
                  continue;
@@ -4837,7 +4923,12 @@ mips_ip (str, ip)
                    max = 0x10000;
                  if (imm_expr.X_op == O_big
                      || imm_expr.X_add_number < -0x8000
-                     || imm_expr.X_add_number >= max)
+                     || imm_expr.X_add_number >= max
+                     || (more
+                         && imm_expr.X_add_number < 0
+                         && mips_isa >= 3
+                         && imm_expr.X_unsigned
+                         && sizeof (imm_expr.X_add_number) <= 4))
                    {
                      if (more)
                        break;
@@ -4917,6 +5008,24 @@ mips_ip (str, ip)
              offset_reloc = BFD_RELOC_MIPS_JMP;
              continue;
 
+           case 'N':           /* 3 bit branch condition code */
+           case 'M':           /* 3 bit compare condition code */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+              if ((unsigned long) imm_expr.X_add_number > 7)
+               {
+                  as_warn ("Condition code > 7 (%ld)",
+                          (long) imm_expr.X_add_number);
+                  imm_expr.X_add_number &= 7;
+               }
+             if (*args == 'N')
+               ip->insn_opcode |= imm_expr.X_add_number << OP_SH_BCC;
+             else
+               ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CCC;
+              imm_expr.X_op = O_absent;
+              s = expr_end;
+              continue;
+
            default:
              fprintf (stderr, "bad char = '%c'\n", *args);
              internalError ();
@@ -5131,30 +5240,32 @@ struct option md_longopts[] = {
   {"mips2", no_argument, NULL, OPTION_MIPS2},
 #define OPTION_MIPS3 (OPTION_MD_BASE + 3)
   {"mips3", no_argument, NULL, OPTION_MIPS3},
-#define OPTION_MCPU (OPTION_MD_BASE + 4)
+#define OPTION_MIPS4 (OPTION_MD_BASE + 4)
+  {"mips4", no_argument, NULL, OPTION_MIPS4},
+#define OPTION_MCPU (OPTION_MD_BASE + 5)
   {"mcpu", required_argument, NULL, OPTION_MCPU},
-#define OPTION_MEMBEDDED_PIC (OPTION_MD_BASE + 5)
+#define OPTION_MEMBEDDED_PIC (OPTION_MD_BASE + 6)
   {"membedded-pic", no_argument, NULL, OPTION_MEMBEDDED_PIC},
-#define OPTION_TRAP (OPTION_MD_BASE + 8)
+#define OPTION_TRAP (OPTION_MD_BASE + 9)
   {"trap", no_argument, NULL, OPTION_TRAP},
   {"no-break", no_argument, NULL, OPTION_TRAP},
-#define OPTION_BREAK (OPTION_MD_BASE + 9)
+#define OPTION_BREAK (OPTION_MD_BASE + 10)
   {"break", no_argument, NULL, OPTION_BREAK},
   {"no-trap", no_argument, NULL, OPTION_BREAK},
-#define OPTION_EB (OPTION_MD_BASE + 10)
+#define OPTION_EB (OPTION_MD_BASE + 11)
   {"EB", no_argument, NULL, OPTION_EB},
-#define OPTION_EL (OPTION_MD_BASE + 11)
+#define OPTION_EL (OPTION_MD_BASE + 12)
   {"EL", no_argument, NULL, OPTION_EL},
-#define OPTION_M4650 (OPTION_MD_BASE + 12)
+#define OPTION_M4650 (OPTION_MD_BASE + 13)
   {"m4650", no_argument, NULL, OPTION_M4650},
-#define OPTION_NO_M4650 (OPTION_MD_BASE + 13)
+#define OPTION_NO_M4650 (OPTION_MD_BASE + 14)
   {"no-m4650", no_argument, NULL, OPTION_NO_M4650},
 
 #ifdef OBJ_ELF
-#define OPTION_CALL_SHARED (OPTION_MD_BASE + 6)
+#define OPTION_CALL_SHARED (OPTION_MD_BASE + 7)
   {"KPIC", no_argument, NULL, OPTION_CALL_SHARED},
   {"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
-#define OPTION_NON_SHARED (OPTION_MD_BASE + 7)
+#define OPTION_NON_SHARED (OPTION_MD_BASE + 8)
   {"non_shared", no_argument, NULL, OPTION_NON_SHARED},
 #endif
 
@@ -5233,6 +5344,12 @@ md_parse_option (c, arg)
        mips_cpu = 4000;
       break;
 
+    case OPTION_MIPS4:
+      mips_isa = 4;
+      if (mips_cpu == -1)
+       mips_cpu = 8000;
+      break;
+
     case OPTION_MCPU:
       {
        char *p;
@@ -5250,6 +5367,13 @@ md_parse_option (c, arg)
            mips_cpu = -1;
            switch (*p)
              {
+             case '1':
+               if (strcmp (p, "10000") == 0
+                   || strcmp (p, "10k") == 0
+                   || strcmp (p, "10K") == 0)
+                 mips_cpu = 10000;
+               break;
+
              case '2':
                if (strcmp (p, "2000") == 0
                    || strcmp (p, "2k") == 0
@@ -5288,6 +5412,13 @@ md_parse_option (c, arg)
                  mips_cpu = 6000;
                break;
 
+             case '8':
+               if (strcmp (p, "8000") == 0
+                   || strcmp (p, "8k") == 0
+                   || strcmp (p, "8K") == 0)
+                 mips_cpu = 8000;
+               break;
+
              case 'o':
                if (strcmp (p, "orion") == 0)
                  mips_cpu = 4600;
@@ -5378,6 +5509,9 @@ MIPS options:\n\
 -mips1, -mcpu=r{2,3}000        generate code for r2000 and r3000\n\
 -mips2, -mcpu=r6000    generate code for r6000\n\
 -mips3, -mcpu=r4000    generate code for r4000\n\
+-mips4, -mcpu=r8000    generate code for r8000\n\
+-m4650                 permit -m4650 instructions\n\
+-no-m4650              do not permit -m4650 instructions\n\
 -O0                    remove unneeded NOPs, do not swap branches\n\
 -O                     remove unneeded NOPs and swap branches\n\
 --trap, --no-break     trap exception on div by 0 and mult overflow\n\
@@ -6124,7 +6258,7 @@ s_mipsset (x)
       isa = atoi (name + 4);
       if (isa == 0)
        mips_isa = file_mips_isa;
-      else if (isa < 1 || isa > 3)
+      else if (isa < 1 || isa > 4)
        as_bad ("unknown ISA level");
       else
        mips_isa = isa;
@@ -6368,6 +6502,61 @@ md_section_align (seg, addr)
    relaxing here, and the final size is encoded in the subtype
    information.  */
 
+/* Utility routine, called from above as well.  If called while the
+   input file is still being read, it's only an approximation.  (For
+   example, a symbol may later become defined which appeared to be
+   undefined earlier.)  */
+static int nopic_need_relax (sym)
+     symbolS *sym;
+{
+  if (sym == 0)
+    return 0;
+
+#ifdef GPOPT
+  {
+    const char *symname;
+    int change;
+
+    /* Find out whether this symbol can be referenced off the GP
+       register.  It can be if it is smaller than the -G size or if it
+       is in the .sdata or .sbss section.  Certain symbols can not be
+       referenced off the GP, although it appears as though they can.  */
+    symname = S_GET_NAME (sym);
+    if (symname != (const char *) NULL
+       && (strcmp (symname, "eprol") == 0
+           || strcmp (symname, "etext") == 0
+           || strcmp (symname, "_gp") == 0
+           || strcmp (symname, "edata") == 0
+           || strcmp (symname, "_fbss") == 0
+           || strcmp (symname, "_fdata") == 0
+           || strcmp (symname, "_ftext") == 0
+           || strcmp (symname, "end") == 0
+           || strcmp (symname, "_gp_disp") == 0))
+      change = 1;
+    else if (! S_IS_DEFINED (sym)
+            && ((sym->ecoff_extern_size != 0
+                 && sym->ecoff_extern_size <= g_switch_value)
+                || (S_GET_VALUE (sym) != 0
+                    && S_GET_VALUE (sym) <= g_switch_value)))
+      change = 0;
+    else
+      {
+       const char *segname;
+
+       segname = segment_name (S_GET_SEGMENT (sym));
+       assert (strcmp (segname, ".lit8") != 0
+               && strcmp (segname, ".lit4") != 0);
+       change = (strcmp (segname, ".sdata") != 0
+                 && strcmp (segname, ".sbss") != 0);
+      }
+    return change;
+  }
+#else /* ! defined (GPOPT) */
+  /* We are not optimizing for the GP register.  */
+  return 1;
+#endif /* ! defined (GPOPT) */  
+}
+
 /*ARGSUSED*/
 int
 md_estimate_size_before_relax (fragp, segtype)
@@ -6378,46 +6567,7 @@ md_estimate_size_before_relax (fragp, segtype)
 
   if (mips_pic == NO_PIC)
     {
-#ifdef GPOPT
-      const char *symname;
-
-      /* Find out whether this symbol can be referenced off the GP
-        register.  It can be if it is smaller than the -G size or if
-        it is in the .sdata or .sbss section.  Certain symbols can
-        not be referenced off the GP, although it appears as though
-        they can.  */
-      symname = S_GET_NAME (fragp->fr_symbol);
-      if (symname != (const char *) NULL
-         && (strcmp (symname, "eprol") == 0
-             || strcmp (symname, "etext") == 0
-             || strcmp (symname, "_gp") == 0
-             || strcmp (symname, "edata") == 0
-             || strcmp (symname, "_fbss") == 0
-             || strcmp (symname, "_fdata") == 0
-             || strcmp (symname, "_ftext") == 0
-             || strcmp (symname, "end") == 0
-             || strcmp (symname, "_gp_disp") == 0))
-       change = 1;
-      else if (! S_IS_DEFINED (fragp->fr_symbol)
-              && ((fragp->fr_symbol->ecoff_extern_size != 0
-                   && fragp->fr_symbol->ecoff_extern_size <= g_switch_value)
-                  || (S_GET_VALUE (fragp->fr_symbol) != 0
-                      && S_GET_VALUE (fragp->fr_symbol) <= g_switch_value)))
-       change = 0;
-      else
-       {
-         const char *segname;
-
-         segname = segment_name (S_GET_SEGMENT (fragp->fr_symbol));
-         assert (strcmp (segname, ".lit8") != 0
-                 && strcmp (segname, ".lit4") != 0);
-         change = (strcmp (segname, ".sdata") != 0
-                   && strcmp (segname, ".sbss") != 0);
-       }
-#else /* ! defined (GPOPT) */
-      /* We are not optimizing for the GP register.  */
-      change = 1;
-#endif /* ! defined (GPOPT) */  
+      change = nopic_need_relax (fragp->fr_symbol);
     }
   else if (mips_pic == SVR4_PIC)
     {
This page took 0.931701 seconds and 4 git commands to generate.