aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-mips.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/config/tc-mips.c')
-rw-r--r--gas/config/tc-mips.c203
1 files changed, 124 insertions, 79 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 3a853f2..6a5e79f 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -405,12 +405,27 @@ gp_reference (ep)
{
#ifdef OBJ_ECOFF
symbolS *sym;
+ const char *symname;
const char *segname;
sym = ep->X_add_symbol;
if (sym == (symbolS *) NULL
|| ep->X_subtract_symbol != (symbolS *) NULL)
return 0;
+
+ /* 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))
+ return 0;
if (! S_IS_DEFINED (sym)
&& S_GET_VALUE (sym) != 0
&& S_GET_VALUE (sym) <= g_switch_value)
@@ -883,13 +898,28 @@ macro (ip)
macro_build (&icnt, &offset_expr, "bgez", "s,p", sreg);
return;
}
+ if (sreg == 0)
+ {
+ macro_build (&icnt, &offset_expr, "blez", "s,p", treg);
+ return;
+ }
macro_build (&icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
break;
case M_BGT_I:
+ /* check for > max integer */
+ if (imm_expr.X_add_number == 0x7fffffff)
+ {
+ do_false:
+ /* result is always false */
+ as_warn ("Branch %s is always false (nop)", ip->insn_mo->name);
+ macro_build (&icnt, NULL, "nop", "", 0);
+ return;
+ }
imm_expr.X_add_number++;
/* FALLTHROUGH */
+
case M_BGE_I:
if (imm_expr.X_add_number == 0)
{
@@ -901,26 +931,39 @@ macro (ip)
macro_build (&icnt, &offset_expr, "bgtz", "s,p", sreg);
return;
}
+ if (imm_expr.X_add_number == 0x80000000)
+ {
+ do_true:
+ /* result is always true */
+ as_warn ("Branch %s is always true", ip->insn_mo->name);
+ macro_build (&icnt, &offset_expr, "b", "p");
+ return;
+ }
set_at (&icnt, sreg);
macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
break;
case M_BGEU:
if (treg == 0)
+ goto do_true;
+ if (sreg == 0)
{
- macro_build (&icnt, &offset_expr, "b", "p");
+ macro_build (&icnt, &offset_expr, "beq", "s,t,p", 0, treg);
return;
}
macro_build (&icnt, NULL, "sltu", "d,v,t", AT, sreg, treg);
macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
break;
+ case M_BGTU_I:
+ if (sreg == 0 || imm_expr.X_add_number == 0xffffffff)
+ goto do_false;
+ imm_expr.X_add_number++;
+ /* FALLTHROUGH */
+
case M_BGEU_I:
if (imm_expr.X_add_number == 0)
- {
- macro_build (&icnt, &offset_expr, "b", "p");
- return;
- }
+ goto do_true;
if (imm_expr.X_add_number == 1)
{
macro_build (&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
@@ -936,6 +979,11 @@ macro (ip)
macro_build (&icnt, &offset_expr, "bgtz", "s,p", sreg);
return;
}
+ if (sreg == 0)
+ {
+ macro_build (&icnt, &offset_expr, "bltz", "s,p", treg);
+ return;
+ }
macro_build (&icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
break;
@@ -946,50 +994,44 @@ macro (ip)
macro_build (&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
return;
}
+ if (sreg == 0)
+ goto do_false;
macro_build (&icnt, NULL, "sltu", "d,v,t", AT, treg, sreg);
macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
break;
- case M_BGTU_I:
- if (imm_expr.X_add_number == 0)
- {
- macro_build (&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
- return;
- }
- if (imm_expr.X_add_number == -1)
- {
- /* NOP */
- if (mips_noreorder)
- as_warn ("Instruction %s is a nop; deleted", ip->insn_mo->name);
- return;
- }
- imm_expr.X_add_number++;
- set_at_unsigned (&icnt, sreg);
- macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
- break;
-
case M_BLE:
if (treg == 0)
{
macro_build (&icnt, &offset_expr, "blez", "s,p", sreg);
return;
}
+ if (sreg == 0)
+ {
+ macro_build (&icnt, &offset_expr, "bgez", "s,p", treg);
+ return;
+ }
macro_build (&icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
break;
case M_BLE_I:
+ if (imm_expr.X_add_number == 0x7fffffff)
+ goto do_true;
+ imm_expr.X_add_number++;
+ /* FALLTHROUGH */
+
+ case M_BLT_I:
if (imm_expr.X_add_number == 0)
{
- macro_build (&icnt, &offset_expr, "blez", "s,p", sreg);
+ macro_build (&icnt, &offset_expr, "bltz", "s,p", sreg);
return;
}
- if (imm_expr.X_add_number == -1)
+ if (imm_expr.X_add_number == 1)
{
- macro_build (&icnt, &offset_expr, "bltz", "s,p", sreg);
+ macro_build (&icnt, &offset_expr, "blez", "s,p", sreg);
return;
}
- imm_expr.X_add_number++;
set_at (&icnt, sreg);
macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
break;
@@ -1000,22 +1042,26 @@ macro (ip)
macro_build (&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
return;
}
+ if (sreg == 0)
+ goto do_true;
macro_build (&icnt, NULL, "sltu", "d,v,t", AT, treg, sreg);
macro_build (&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
break;
case M_BLEU_I:
+ if (sreg == 0 || imm_expr.X_add_number == 0xffffffff)
+ goto do_true;
+ imm_expr.X_add_number++;
+ /* FALLTHROUGH */
+
+ case M_BLTU_I:
if (imm_expr.X_add_number == 0)
+ goto do_false;
+ if (imm_expr.X_add_number == 1)
{
macro_build (&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
return;
}
- if (imm_expr.X_add_number == -1)
- {
- macro_build (&icnt, &offset_expr, "b", "p");
- return;
- }
- imm_expr.X_add_number++;
set_at_unsigned (&icnt, sreg);
macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
break;
@@ -1026,54 +1072,27 @@ macro (ip)
macro_build (&icnt, &offset_expr, "bltz", "s,p", sreg);
return;
}
- macro_build (&icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
- macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
- break;
-
- case M_BLT_I:
- if (imm_expr.X_add_number == 0)
- {
- macro_build (&icnt, &offset_expr, "bltz", "s,p", sreg);
- return;
- }
- if (imm_expr.X_add_number == 1)
+ if (sreg == 0)
{
- macro_build (&icnt, &offset_expr, "blez", "s,p", sreg);
+ macro_build (&icnt, &offset_expr, "bgtz", "s,p", treg);
return;
}
- set_at (&icnt, sreg);
+ macro_build (&icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
break;
case M_BLTU:
if (treg == 0)
+ goto do_false;
+ if (sreg == 0)
{
- /* NOP */
- if (mips_noreorder)
- as_warn ("Instruction %s is a nop; deleted", ip->insn_mo->name);
+ macro_build (&icnt, &offset_expr, "bne", "s,t,p", 0, treg);
return;
}
macro_build (&icnt, NULL, "sltu", "d,v,t", AT, sreg, treg);
macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
break;
- case M_BLTU_I:
- if (imm_expr.X_add_number == 0)
- {
- /* NOP */
- if (mips_noreorder)
- as_warn ("Instruction %s is a nop; deleted", ip->insn_mo->name);
- return;
- }
- if (imm_expr.X_add_number == 1)
- {
- macro_build (&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
- return;
- }
- set_at_unsigned (&icnt, sreg);
- macro_build (&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
- break;
-
case M_DIV_3:
case M_REM_3:
if (treg == 0)
@@ -1318,13 +1337,19 @@ macro (ip)
break;
case M_L_DOB:
+ /* Even on a big endian machine $fn comes before $fn+1. We have
+ to adjust when loading from memory. */
save_reorder_condition = mips_noreorder;
mips_noreorder = 1;
- macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg, breg);
+ macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)",
+ byte_order == LITTLE_ENDIAN ? treg : treg + 1,
+ breg);
/* unecessary implicit nop */
mips_noreorder = save_reorder_condition;
offset_expr.X_add_number += 4;
- macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg + 1, breg);
+ macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)",
+ byte_order == LITTLE_ENDIAN ? treg + 1 : treg,
+ breg);
return;
case M_L_DAB:
@@ -1356,13 +1381,19 @@ macro (ip)
macro_build (&icnt, NULL, "addu", "d,v,t", AT, AT, breg);
tempreg = AT;
}
+ /* Even on a big endian machine $fn comes before $fn+1. We have
+ to adjust when loading from memory. */
save_reorder_condition = mips_noreorder;
mips_noreorder = 1;
- macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg, tempreg);
+ macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)",
+ byte_order == LITTLE_ENDIAN ? treg : treg + 1,
+ tempreg);
/* unecessary implicit nop */
mips_noreorder = save_reorder_condition;
offset_expr.X_add_number += 4;
- macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg + 1, tempreg);
+ macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)",
+ byte_order == LITTLE_ENDIAN ? treg + 1 : treg,
+ tempreg);
if (tempreg == AT)
break;
return;
@@ -1469,9 +1500,15 @@ macro (ip)
break;
case M_S_DOB:
- macro_build (&icnt, &offset_expr, "swc1", "T,o(b)", treg, breg);
+ /* Even on a big endian machine $fn comes before $fn+1. We have
+ to adjust when storing to memory. */
+ macro_build (&icnt, &offset_expr, "swc1", "T,o(b)",
+ byte_order == LITTLE_ENDIAN ? treg : treg + 1,
+ breg);
offset_expr.X_add_number += 4;
- macro_build (&icnt, &offset_expr, "swc1", "T,o(b)", treg + 1, breg);
+ macro_build (&icnt, &offset_expr, "swc1", "T,o(b)",
+ byte_order == LITTLE_ENDIAN ? treg + 1 : treg,
+ breg);
return;
case M_S_DAB:
@@ -1493,9 +1530,15 @@ macro (ip)
macro_build (&icnt, NULL, "addu", "d,v,t", AT, AT, breg);
tempreg = AT;
}
- macro_build (&icnt, &offset_expr, "swc1", "T,o(b)", treg, tempreg);
+ /* Even on a big endian machine $fn comes before $fn+1. We have
+ to adjust when storing to memory. */
+ macro_build (&icnt, &offset_expr, "swc1", "T,o(b)",
+ byte_order == LITTLE_ENDIAN ? treg : treg + 1,
+ tempreg);
offset_expr.X_add_number += 4;
- macro_build (&icnt, &offset_expr, "swc1", "T,o(b)", treg + 1, tempreg);
+ macro_build (&icnt, &offset_expr, "swc1", "T,o(b)",
+ byte_order == LITTLE_ENDIAN ? treg + 1 : treg,
+ tempreg);
if (tempreg == AT)
break;
return;
@@ -1520,7 +1563,8 @@ macro (ip)
}
if (sreg == 0)
{
- /* result is always false */
+ as_warn ("Instruction %s: result is always false",
+ ip->insn_mo->name);
macro_build (&icnt, NULL, "move", "d,s", dreg, 0);
return;
}
@@ -1610,7 +1654,7 @@ macro (ip)
s = "sltu";
sle:
macro_build (&icnt, NULL, s, "d,v,t", dreg, treg, sreg);
- macro_build (&icnt, &imm_expr, "xori", "t,r,i", dreg, dreg);
+ macro_build (&icnt, &expr1, "xori", "t,r,i", dreg, dreg);
return;
case M_SLE_I: /* sreg <= I <==> I >= sreg <==> not (I < sreg) */
@@ -1621,7 +1665,7 @@ macro (ip)
slei:
load_register (&icnt, ip, AT, &imm_expr);
macro_build (&icnt, NULL, s, "d,v,t", dreg, AT, sreg);
- macro_build (&icnt, &offset_expr, "xori", "t,r,i", dreg, dreg);
+ macro_build (&icnt, &expr1, "xori", "t,r,i", dreg, dreg);
break;
case M_SLT_I:
@@ -1664,7 +1708,8 @@ macro (ip)
}
if (sreg == 0)
{
- /* result is always true */
+ as_warn ("Instruction %s: result is always true",
+ ip->insn_mo->name);
macro_build (&icnt, &expr1, "addiu", "t,r,j", dreg, 0);
return;
}
@@ -3163,7 +3208,7 @@ s_file (x)
int line;
line = get_number ();
- s_app_file ();
+ s_app_file (0);
}