mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-01-31 14:04:12 +00:00
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.
This commit is contained in:
parent
b79de3a178
commit
d8a1c247ae
@ -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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user