aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorKen Raeburn <raeburn@cygnus>1995-04-11 01:29:49 +0000
committerKen Raeburn <raeburn@cygnus>1995-04-11 01:29:49 +0000
commitd8a1c247aef292a99c2a132bd7d9a950234c7c7e (patch)
treedd01e4dbf5ad6714a5272678298768b05ff413ef /gas
parentb79de3a17822e3ed005ad21a7730772969b8e649 (diff)
downloadgdb-d8a1c247aef292a99c2a132bd7d9a950234c7c7e.zip
gdb-d8a1c247aef292a99c2a132bd7d9a950234c7c7e.tar.gz
gdb-d8a1c247aef292a99c2a132bd7d9a950234c7c7e.tar.bz2
Fix for PR6697:
(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.
Diffstat (limited to 'gas')
-rw-r--r--gas/config/tc-mips.c380
1 files changed, 265 insertions, 115 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index f3677ec..4fb2c0a 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -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)
{