diff options
author | Maciej W. Rozycki <macro@linux-mips.org> | 2005-04-13 18:17:10 +0000 |
---|---|---|
committer | Maciej W. Rozycki <macro@linux-mips.org> | 2005-04-13 18:17:10 +0000 |
commit | 2051e8c45faf97a1f6edb065c23a6a5e8fb8c484 (patch) | |
tree | 131f277bc01126fddb04b29d97feeee206ad4eb8 /gas/config/tc-mips.c | |
parent | a63027e547181bee6b09e1c4441df4934e38edcd (diff) | |
download | fsf-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.c | 87 |
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; |