Catch some more cases where we can represent a 16 bit immediate operand as

8 bit sign extended.
This commit is contained in:
Alan Modra 2000-02-26 04:00:13 +00:00
parent 8d75d12d1b
commit 773f551c1d
2 changed files with 82 additions and 15 deletions

View File

@ -1,3 +1,18 @@
2000-02-26 Alan Modra <alan@spri.levels.unisa.edu.au>
* config/tc-i386.c (i386_immediate): Move constant operand sizing
from here..
(md_assemble): To here, before template operands are matched.
Also ensure a constant immediate is sign extended when we know the
size is at most 16 bits. This is to catch cases like "add
$0xffc0,%ax" where we don't know the size, and thus that the
immediate can be represented as Imm8S until after parsing the
register operand.
(i386_displacement): Similarly sign extend 16 bit constant
displacements.
(md_assemble): Relax 16-bit jump constant range check to suit sign
extended displacements.
2000-02-26 Andreas Jaeger <aj@suse.de>
* doc/c-mips.texi (MIPS Opts): Fix typo in last patch.

View File

@ -1305,6 +1305,61 @@ md_assemble (line)
i.seg[1] = temp_seg;
}
}
if (i.imm_operands)
{
/* Try to ensure constant immediates are represented in the smallest
opcode possible. */
char guess_suffix = 0;
int op;
if (i.suffix)
guess_suffix = i.suffix;
else if (i.reg_operands)
{
/* Figure out a suffix from the last register operand specified.
We can't do this properly yet, ie. excluding InOutPortReg,
but the following works for instructions with immediates.
In any case, we can't set i.suffix yet. */
for (op = i.operands; --op >= 0; )
if (i.types[op] & Reg)
{
if (i.types[op] & Reg8)
guess_suffix = BYTE_MNEM_SUFFIX;
else if (i.types[op] & Reg16)
guess_suffix = WORD_MNEM_SUFFIX;
break;
}
}
for (op = i.operands; --op >= 0; )
if ((i.types[op] & Imm)
&& i.op[op].imms->X_op == O_constant)
{
/* If a suffix is given, this operand may be shortened. */
switch (guess_suffix)
{
case WORD_MNEM_SUFFIX:
i.types[op] |= Imm16;
break;
case BYTE_MNEM_SUFFIX:
i.types[op] |= Imm16 | Imm8 | Imm8S;
break;
}
/* If this operand is at most 16 bits, convert it to a
signed 16 bit number before trying to see whether it will
fit in an even smaller size. This allows a 16-bit operand
such as $0xffe0 to be recognised as within Imm8S range. */
if ((i.types[op] & Imm16)
&& (i.op[op].imms->X_add_number & ~(offsetT)0xffff) == 0)
{
i.op[op].imms->X_add_number =
(((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
}
i.types[op] |= smallest_imm_type ((long) i.op[op].imms->X_add_number);
}
}
overlap0 = 0;
overlap1 = 0;
overlap2 = 0;
@ -2200,7 +2255,9 @@ md_assemble (line)
{
long n = (long) i.op[1].imms->X_add_number;
if (size == 2 && !fits_in_unsigned_word (n))
if (size == 2
&& !fits_in_unsigned_word (n)
&& !fits_in_signed_word (n))
{
as_bad (_("16-bit jump out of range"));
return;
@ -2530,20 +2587,7 @@ i386_immediate (imm_start)
int bigimm = Imm32;
if (flag_16bit_code ^ (i.prefix[DATA_PREFIX] != 0))
bigimm = Imm16;
i.types[this_operand] |=
(bigimm | smallest_imm_type ((long) exp->X_add_number));
/* If a suffix is given, this operand may be shortened. */
switch (i.suffix)
{
case WORD_MNEM_SUFFIX:
i.types[this_operand] |= Imm16;
break;
case BYTE_MNEM_SUFFIX:
i.types[this_operand] |= Imm16 | Imm8 | Imm8S;
break;
}
i.types[this_operand] |= bigimm;
}
#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
else if (
@ -2784,6 +2828,14 @@ i386_displacement (disp_start, disp_end)
if (exp->X_op == O_constant)
{
if (i.types[this_operand] & Disp16)
{
/* We know this operand is at most 16 bits, so convert to a
signed 16 bit number before trying to see whether it will
fit in an even smaller size. */
exp->X_add_number =
(((exp->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
}
if (fits_in_signed_byte (exp->X_add_number))
i.types[this_operand] |= Disp8;
}