aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-mips.c
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2005-04-13 18:17:10 +0000
committerMaciej W. Rozycki <macro@linux-mips.org>2005-04-13 18:17:10 +0000
commit2051e8c45faf97a1f6edb065c23a6a5e8fb8c484 (patch)
tree131f277bc01126fddb04b29d97feeee206ad4eb8 /gas/config/tc-mips.c
parenta63027e547181bee6b09e1c4441df4934e38edcd (diff)
downloadfsf-binutils-gdb-2051e8c45faf97a1f6edb065c23a6a5e8fb8c484.zip
fsf-binutils-gdb-2051e8c45faf97a1f6edb065c23a6a5e8fb8c484.tar.gz
fsf-binutils-gdb-2051e8c45faf97a1f6edb065c23a6a5e8fb8c484.tar.bz2
gas/:
* config/tc-mips.c (IS_ZEXT_32BIT_NUM): New macro. (normalize_address_expr): New function to sign-extend address offsets that fit into 32 bits in 32-bit mode. (macro_build_ldst_constoffset): Use normalize_address_expr() instead of a handcoded sequence. (load_register): Likewise. Report oversized numbers in a useful way. (macro) [ld_st, ldd_std]: Reject all oversized offsets, not only for constant addresses. Report oversized numbers in a useful way. (mips_ip): Use normalize_address_expr() for addresses. gas/testsuite/: * gas/mips/ldstla-32.s: Exclude offsets that are now meant to fail and include more instructions/offsets that are meant to succeed. Use $4 instead $3 to avoid register dependencies. * gas/mips/ldstla-32.d: Update accordingly. * gas/mips/ldstla-32-shared.d: Likewise. * gas/mips/ldstla-32-mips3.d: New test based on the above, except for mips3. * gas/mips/ldstla-32-mips3-shared.d: Similarly, for PIC. * gas/mips/ldstla-32-mips3.s: Source for the new tests. * gas/mips/ldstla-32-1.s: New test for offsets that are meant to fail. * gas/mips/ldstla-32-mips3-1.s: Likewise, for mips3. * gas/mips/ldstla-32-1.l: Stderr output for the new test. * gas/mips/ldstla-32-mips3-1.l: Likewise. * gas/mips/mips.exp: Run the new tests.
Diffstat (limited to 'gas/config/tc-mips.c')
-rw-r--r--gas/config/tc-mips.c87
1 files changed, 54 insertions, 33 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index d622d4b..a13b06e 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -861,6 +861,11 @@ static int mips_relax_branch;
(((x) &~ (offsetT) 0x7fff) == 0 \
|| (((x) &~ (offsetT) 0x7fff) == ~ (offsetT) 0x7fff))
+/* Is the given value a zero-extended 32-bit value? Or a negated one? */
+#define IS_ZEXT_32BIT_NUM(x) \
+ (((x) &~ (offsetT) 0xffffffff) == 0 \
+ || (((x) &~ (offsetT) 0xffffffff) == ~ (offsetT) 0xffffffff))
+
/* Replace bits MASK << SHIFT of STRUCT with the equivalent bits in
VALUE << SHIFT. VALUE is evaluated exactly once. */
#define INSERT_BITS(STRUCT, VALUE, MASK, SHIFT) \
@@ -3253,6 +3258,33 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
append_insn (&insn, ep, r);
}
+static void
+/*
+ * Sign-extend 32-bit mode constants that have bit 31 set and all
+ * higher bits unset.
+ */
+normalize_constant_expr (expressionS *ex)
+{
+ if ((ex->X_op == O_constant && HAVE_32BIT_GPRS)
+ && IS_ZEXT_32BIT_NUM (ex->X_add_number))
+ ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
+ - 0x80000000);
+}
+
+/*
+ * Sign-extend 32-bit mode address offsets that have bit 31 set and
+ * all higher bits unset.
+ */
+static void
+normalize_address_expr (expressionS *ex)
+{
+ if (((ex->X_op == O_constant && HAVE_32BIT_ADDRESSES)
+ || (ex->X_op == O_symbol && HAVE_32BIT_SYMBOLS))
+ && IS_ZEXT_32BIT_NUM (ex->X_add_number))
+ ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
+ - 0x80000000);
+}
+
/*
* Generate a "jalr" instruction with a relocation hint to the called
* function. This occurs in NewABI PIC code.
@@ -3338,15 +3370,8 @@ macro_build_ldst_constoffset (expressionS *ep, const char *op,
assert (ep->X_op == O_constant);
/* Sign-extending 32-bit constants makes their handling easier. */
- if (! dbl && ! ((ep->X_add_number & ~((bfd_vma) 0x7fffffff))
- == ~((bfd_vma) 0x7fffffff)))
- {
- if (ep->X_add_number & ~((bfd_vma) 0xffffffff))
- as_bad (_("constant too large"));
-
- ep->X_add_number = (((ep->X_add_number & 0xffffffff) ^ 0x80000000)
- - 0x80000000);
- }
+ if (!dbl)
+ normalize_constant_expr (ep);
/* Right now, this routine can only handle signed 32-bit constants. */
if (! IS_SEXT_32BIT_NUM(ep->X_add_number + 0x8000))
@@ -3392,14 +3417,6 @@ set_at (int reg, int unsignedp)
}
}
-static void
-normalize_constant_expr (expressionS *ex)
-{
- if (ex->X_op == O_constant && HAVE_32BIT_GPRS)
- ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
- - 0x80000000);
-}
-
/* Warn if an expression is not a constant. */
static void
@@ -3504,15 +3521,8 @@ load_register (int reg, expressionS *ep, int dbl)
assert (ep->X_op == O_constant);
/* Sign-extending 32-bit constants makes their handling easier. */
- if (! dbl && ! ((ep->X_add_number & ~((bfd_vma) 0x7fffffff))
- == ~((bfd_vma) 0x7fffffff)))
- {
- if (ep->X_add_number & ~((bfd_vma) 0xffffffff))
- as_bad (_("constant too large"));
-
- ep->X_add_number = (((ep->X_add_number & 0xffffffff) ^ 0x80000000)
- - 0x80000000);
- }
+ if (!dbl)
+ normalize_constant_expr (ep);
if (IS_SEXT_16BIT_NUM (ep->X_add_number))
{
@@ -3541,10 +3551,11 @@ load_register (int reg, expressionS *ep, int dbl)
/* The value is larger than 32 bits. */
- if (HAVE_32BIT_GPRS)
+ if (!dbl || HAVE_32BIT_GPRS)
{
- as_bad (_("Number (0x%lx) larger than 32 bits"),
- (unsigned long) ep->X_add_number);
+ as_bad (_("Number (0x%lx%08lx) larger than 32 bits"),
+ (unsigned long) (ep->X_add_number >> 32),
+ (unsigned long) (ep->X_add_number & 0xffffffff));
macro_build (ep, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
return;
}
@@ -5785,16 +5796,19 @@ macro (struct mips_cl_insn *ip)
offset_expr.X_op = O_constant;
}
+ if (HAVE_32BIT_ADDRESSES
+ && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
+ as_bad (_("Number (0x%lx%08lx) larger than 32 bits"),
+ (unsigned long) (offset_expr.X_add_number >> 32),
+ (unsigned long) (offset_expr.X_add_number & 0xffffffff));
+
/* A constant expression in PIC code can be handled just as it
is in non PIC code. */
if (offset_expr.X_op == O_constant)
{
- if (HAVE_32BIT_ADDRESSES
- && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
- as_bad (_("constant too large"));
-
expr1.X_add_number = ((offset_expr.X_add_number + 0x8000)
& ~(bfd_vma) 0xffff);
+ normalize_address_expr (&expr1);
load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
@@ -6373,6 +6387,12 @@ macro (struct mips_cl_insn *ip)
offset_expr.X_op = O_constant;
}
+ if (HAVE_32BIT_ADDRESSES
+ && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
+ as_bad (_("Number (0x%lx%08lx) larger than 32 bits"),
+ (unsigned long) (offset_expr.X_add_number >> 32),
+ (unsigned long) (offset_expr.X_add_number & 0xffffffff));
+
/* Even on a big endian machine $fn comes before $fn+1. We have
to adjust when loading from memory. We set coproc if we must
load $fn+1 first. */
@@ -8556,6 +8576,7 @@ do_msbd:
case 'A':
my_getExpression (&offset_expr, s);
+ normalize_address_expr (&offset_expr);
*imm_reloc = BFD_RELOC_32;
s = expr_end;
continue;