Improve gas error messages for invalid instructions.

* cpu-ia64-opc.c (elf64_ia64_operands}: Fix typo: error string for
	C8 said "1" instead of "8".  Clarify error string for IMM22:
	"signed integer" instead of just "integer".
	* config/tc-ia64.c (enum operand_match_result): New type.
	(operand_match): Change return type to operand_match_result.
	Fix all returns appropriately, adding support for returning the
	out-of-range result.
	(parse_operands): New locals result, error_pos, out_of_range_pos,
	curr_out_of_range_pos.  Rewrite operand matching loop to give better
	error messages.
	* ia64-opc-d.c (ia64_opcodes_d): Break the "add" pattern into two
	separate variants: one for IMM22 and the other for IMM14.
	* ia64-asmtab.c: Regenerate.
This commit is contained in:
Jim Wilson 2001-02-22 03:16:21 +00:00
parent aacc1edd3a
commit 87f8eb977e
7 changed files with 4146 additions and 4012 deletions

View File

@ -1,3 +1,9 @@
2001-02-21 David Mosberger <davidm@hpl.hp.com>
* cpu-ia64-opc.c (elf64_ia64_operands}: Fix typo: error string for
C8 said "1" instead of "8". Clarify error string for IMM22:
"signed integer" instead of just "integer".
2001-02-20 Andreas Jaeger <aj@suse.de>
* elf64-x86-64.c (elf64_x86_64_finish_dynamic_symbol): Don't make

View File

@ -421,7 +421,7 @@ const struct ia64_operand elf64_ia64_operands[IA64_OPND_COUNT] =
{ CST, ins_const, ext_const, "ar.ccv", {{ 0, 0}}, 0, "ar.ccv" },
{ CST, ins_const, ext_const, "ar.pfs", {{ 0, 0}}, 0, "ar.pfs" },
{ CST, ins_const, ext_const, "1", {{ 0, 0}}, 0, "1" },
{ CST, ins_const, ext_const, "8", {{ 0, 0}}, 0, "1" },
{ CST, ins_const, ext_const, "8", {{ 0, 0}}, 0, "8" },
{ CST, ins_const, ext_const, "16", {{ 0, 0}}, 0, "16" },
{ CST, ins_const, ext_const, "r0", {{ 0, 0}}, 0, "r0" },
{ CST, ins_const, ext_const, "ip", {{ 0, 0}}, 0, "ip" },
@ -551,7 +551,7 @@ const struct ia64_operand elf64_ia64_operands[IA64_OPND_COUNT] =
"a 21-bit unsigned" },
{ ABS, ins_imms, ext_imms, 0, /* IMM22 */
{{ 7, 13}, { 9, 27}, { 5, 22}, { 1, 36}}, SDEC,
"a 22-bit integer" },
"a 22-bit signed integer" },
{ ABS, ins_immu, ext_immu, 0, /* IMMU24 */
{{21, 6}, { 2, 31}, { 1, 36}}, 0,
"a 24-bit unsigned" },

View File

@ -1,3 +1,13 @@
2001-02-21 David Mosberger <davidm@hpl.hp.com>
* config/tc-ia64.c (enum operand_match_result): New type.
(operand_match): Change return type to operand_match_result.
Fix all returns appropriately, adding support for returning the
out-of-range result.
(parse_operands): New locals result, error_pos, out_of_range_pos,
curr_out_of_range_pos. Rewrite operand matching loop to give better
error messages.
2001-02-21 David Mosberger <davidm@hpl.hp.com>
* config/tc-ia64.c (struct unwind): Add member "prologue_count".

View File

@ -124,6 +124,13 @@ enum dynreg_type
DYNREG_NUM_TYPES
};
enum operand_match_result
{
OPERAND_MATCH,
OPERAND_OUT_OF_RANGE,
OPERAND_MISMATCH
};
/* On the ia64, we can't know the address of a text label until the
instructions are packed into a bundle. To handle this, we keep
track of the list of labels that appear in front of each
@ -690,8 +697,9 @@ static void add_unwind_entry PARAMS((unw_rec_list *ptr));
static symbolS *declare_register PARAMS ((const char *name, int regnum));
static void declare_register_set PARAMS ((const char *, int, int));
static unsigned int operand_width PARAMS ((enum ia64_opnd));
static int operand_match PARAMS ((const struct ia64_opcode *idesc,
int index, expressionS *e));
static enum operand_match_result operand_match PARAMS ((const struct ia64_opcode *idesc,
int index,
expressionS *e));
static int parse_operand PARAMS ((expressionS *e));
static struct ia64_opcode * parse_operands PARAMS ((struct ia64_opcode *));
static void build_insn PARAMS ((struct slot *, bfd_vma *));
@ -4740,7 +4748,7 @@ operand_width (opnd)
return bits;
}
static int
static enum operand_match_result
operand_match (idesc, index, e)
const struct ia64_opcode *idesc;
int index;
@ -4757,62 +4765,77 @@ operand_match (idesc, index, e)
case IA64_OPND_AR_CCV:
if (e->X_op == O_register && e->X_add_number == REG_AR + 32)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_AR_PFS:
if (e->X_op == O_register && e->X_add_number == REG_AR + 64)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_GR0:
if (e->X_op == O_register && e->X_add_number == REG_GR + 0)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_IP:
if (e->X_op == O_register && e->X_add_number == REG_IP)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_PR:
if (e->X_op == O_register && e->X_add_number == REG_PR)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_PR_ROT:
if (e->X_op == O_register && e->X_add_number == REG_PR_ROT)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_PSR:
if (e->X_op == O_register && e->X_add_number == REG_PSR)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_PSR_L:
if (e->X_op == O_register && e->X_add_number == REG_PSR_L)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_PSR_UM:
if (e->X_op == O_register && e->X_add_number == REG_PSR_UM)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_C1:
if (e->X_op == O_constant && e->X_add_number == 1)
return 1;
if (e->X_op == O_constant)
{
if (e->X_add_number == 1)
return OPERAND_MATCH;
else
return OPERAND_OUT_OF_RANGE;
}
break;
case IA64_OPND_C8:
if (e->X_op == O_constant && e->X_add_number == 8)
return 1;
if (e->X_op == O_constant)
{
if (e->X_add_number == 8)
return OPERAND_MATCH;
else
return OPERAND_OUT_OF_RANGE;
}
break;
case IA64_OPND_C16:
if (e->X_op == O_constant && e->X_add_number == 16)
return 1;
if (e->X_op == O_constant)
{
if (e->X_add_number == 16)
return OPERAND_MATCH;
else
return OPERAND_OUT_OF_RANGE;
}
break;
/* register operands: */
@ -4820,20 +4843,20 @@ operand_match (idesc, index, e)
case IA64_OPND_AR3:
if (e->X_op == O_register && e->X_add_number >= REG_AR
&& e->X_add_number < REG_AR + 128)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_B1:
case IA64_OPND_B2:
if (e->X_op == O_register && e->X_add_number >= REG_BR
&& e->X_add_number < REG_BR + 8)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_CR3:
if (e->X_op == O_register && e->X_add_number >= REG_CR
&& e->X_add_number < REG_CR + 128)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_F1:
@ -4842,14 +4865,14 @@ operand_match (idesc, index, e)
case IA64_OPND_F4:
if (e->X_op == O_register && e->X_add_number >= REG_FR
&& e->X_add_number < REG_FR + 128)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_P1:
case IA64_OPND_P2:
if (e->X_op == O_register && e->X_add_number >= REG_P
&& e->X_add_number < REG_P + 64)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_R1:
@ -4857,13 +4880,17 @@ operand_match (idesc, index, e)
case IA64_OPND_R3:
if (e->X_op == O_register && e->X_add_number >= REG_GR
&& e->X_add_number < REG_GR + 128)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_R3_2:
if (e->X_op == O_register && e->X_add_number >= REG_GR
&& e->X_add_number < REG_GR + 4)
return 1;
if (e->X_op == O_register && e->X_add_number >= REG_GR)
{
if (e->X_add_number < REG_GR + 4)
return OPERAND_MATCH;
else if (e->X_add_number < REG_GR + 128)
return OPERAND_OUT_OF_RANGE;
}
break;
/* indirect operands: */
@ -4880,12 +4907,12 @@ operand_match (idesc, index, e)
if (e->X_op == O_index && e->X_op_symbol
&& (S_GET_VALUE (e->X_op_symbol) - IND_CPUID
== opnd - IA64_OPND_CPUID_R3))
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_MR3:
if (e->X_op == O_index && !e->X_op_symbol)
return 1;
return OPERAND_MATCH;
break;
/* immediate operands: */
@ -4893,40 +4920,58 @@ operand_match (idesc, index, e)
case IA64_OPND_LEN4:
case IA64_OPND_LEN6:
bits = operand_width (idesc->operands[index]);
if (e->X_op == O_constant
&& (bfd_vma) (e->X_add_number - 1) < ((bfd_vma) 1 << bits))
return 1;
if (e->X_op == O_constant)
{
if ((bfd_vma) (e->X_add_number - 1) < ((bfd_vma) 1 << bits))
return OPERAND_MATCH;
else
return OPERAND_OUT_OF_RANGE;
}
break;
case IA64_OPND_CNT2b:
if (e->X_op == O_constant
&& (bfd_vma) (e->X_add_number - 1) < 3)
return 1;
if (e->X_op == O_constant)
{
if ((bfd_vma) (e->X_add_number - 1) < 3)
return OPERAND_MATCH;
else
return OPERAND_OUT_OF_RANGE;
}
break;
case IA64_OPND_CNT2c:
val = e->X_add_number;
if (e->X_op == O_constant
&& (val == 0 || val == 7 || val == 15 || val == 16))
return 1;
if (e->X_op == O_constant)
{
if ((val == 0 || val == 7 || val == 15 || val == 16))
return OPERAND_MATCH;
else
return OPERAND_OUT_OF_RANGE;
}
break;
case IA64_OPND_SOR:
/* SOR must be an integer multiple of 8 */
if (e->X_add_number & 0x7)
break;
if (e->X_op == O_constant && e->X_add_number & 0x7)
return OPERAND_OUT_OF_RANGE;
case IA64_OPND_SOF:
case IA64_OPND_SOL:
if (e->X_op == O_constant &&
(bfd_vma) e->X_add_number <= 96)
return 1;
if (e->X_op == O_constant)
{
if ((bfd_vma) e->X_add_number <= 96)
return OPERAND_MATCH;
else
return OPERAND_OUT_OF_RANGE;
}
break;
case IA64_OPND_IMMU62:
if (e->X_op == O_constant)
{
if ((bfd_vma) e->X_add_number < ((bfd_vma) 1 << 62))
return 1;
return OPERAND_MATCH;
else
return OPERAND_OUT_OF_RANGE;
}
else
{
@ -4952,10 +4997,10 @@ operand_match (idesc, index, e)
fix->expr = *e;
fix->is_pcrel = 0;
++CURR_SLOT.num_fixups;
return 1;
return OPERAND_MATCH;
}
else if (e->X_op == O_constant)
return 1;
return OPERAND_MATCH;
break;
case IA64_OPND_CCNT5:
@ -4973,59 +5018,78 @@ operand_match (idesc, index, e)
case IA64_OPND_MHTYPE8:
case IA64_OPND_POS6:
bits = operand_width (idesc->operands[index]);
if (e->X_op == O_constant
&& (bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
return 1;
if (e->X_op == O_constant)
{
if ((bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
return OPERAND_MATCH;
else
return OPERAND_OUT_OF_RANGE;
}
break;
case IA64_OPND_IMMU9:
bits = operand_width (idesc->operands[index]);
if (e->X_op == O_constant
&& (bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
if (e->X_op == O_constant)
{
int lobits = e->X_add_number & 0x3;
if (((bfd_vma) e->X_add_number & 0x3C) != 0 && lobits == 0)
e->X_add_number |= (bfd_vma) 0x3;
return 1;
if ((bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
{
int lobits = e->X_add_number & 0x3;
if (((bfd_vma) e->X_add_number & 0x3C) != 0 && lobits == 0)
e->X_add_number |= (bfd_vma) 0x3;
return OPERAND_MATCH;
}
else
return OPERAND_OUT_OF_RANGE;
}
break;
case IA64_OPND_IMM44:
/* least 16 bits must be zero */
if ((e->X_add_number & 0xffff) != 0)
/* XXX technically, this is wrong: we should not be issuing warning
messages until we're sure this instruction pattern is going to
be used! */
as_warn (_("lower 16 bits of mask ignored"));
if (e->X_op == O_constant
&& ((e->X_add_number >= 0
&& (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 44))
|| (e->X_add_number < 0
&& (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 44))))
if (e->X_op == O_constant)
{
/* sign-extend */
if (e->X_add_number >= 0
&& (e->X_add_number & ((bfd_vma) 1 << 43)) != 0)
if (((e->X_add_number >= 0
&& (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 44))
|| (e->X_add_number < 0
&& (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 44))))
{
e->X_add_number |= ~(((bfd_vma) 1 << 44) - 1);
/* sign-extend */
if (e->X_add_number >= 0
&& (e->X_add_number & ((bfd_vma) 1 << 43)) != 0)
{
e->X_add_number |= ~(((bfd_vma) 1 << 44) - 1);
}
return OPERAND_MATCH;
}
return 1;
else
return OPERAND_OUT_OF_RANGE;
}
break;
case IA64_OPND_IMM17:
/* bit 0 is a don't care (pr0 is hardwired to 1) */
if (e->X_op == O_constant
&& ((e->X_add_number >= 0
&& (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 17))
|| (e->X_add_number < 0
&& (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 17))))
if (e->X_op == O_constant)
{
/* sign-extend */
if (e->X_add_number >= 0
&& (e->X_add_number & ((bfd_vma) 1 << 16)) != 0)
if (((e->X_add_number >= 0
&& (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 17))
|| (e->X_add_number < 0
&& (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 17))))
{
e->X_add_number |= ~(((bfd_vma) 1 << 17) - 1);
/* sign-extend */
if (e->X_add_number >= 0
&& (e->X_add_number & ((bfd_vma) 1 << 16)) != 0)
{
e->X_add_number |= ~(((bfd_vma) 1 << 17) - 1);
}
return OPERAND_MATCH;
}
return 1;
else
return OPERAND_OUT_OF_RANGE;
}
break;
@ -5063,18 +5127,18 @@ operand_match (idesc, index, e)
fix->expr = *e;
fix->is_pcrel = 0;
++CURR_SLOT.num_fixups;
return 1;
return OPERAND_MATCH;
}
else if (e->X_op != O_constant
&& ! (e->X_op == O_big && opnd == IA64_OPND_IMM8M1U8))
return 0;
return OPERAND_MISMATCH;
if (opnd == IA64_OPND_IMM8M1U4)
{
/* Zero is not valid for unsigned compares that take an adjusted
constant immediate range. */
if (e->X_add_number == 0)
return 0;
return OPERAND_OUT_OF_RANGE;
/* Sign-extend 32-bit unsigned numbers, so that the following range
checks will work. */
@ -5086,7 +5150,7 @@ operand_match (idesc, index, e)
/* Check for 0x100000000. This is valid because
0x100000000-1 is the same as ((uint32_t) -1). */
if (val == ((bfd_signed_vma) 1 << 32))
return 1;
return OPERAND_MATCH;
val = val - 1;
}
@ -5095,7 +5159,7 @@ operand_match (idesc, index, e)
/* Zero is not valid for unsigned compares that take an adjusted
constant immediate range. */
if (e->X_add_number == 0)
return 0;
return OPERAND_OUT_OF_RANGE;
/* Check for 0x10000000000000000. */
if (e->X_op == O_big)
@ -5105,9 +5169,9 @@ operand_match (idesc, index, e)
&& generic_bignum[2] == 0
&& generic_bignum[3] == 0
&& generic_bignum[4] == 1)
return 1;
return OPERAND_MATCH;
else
return 0;
return OPERAND_OUT_OF_RANGE;
}
else
val = e->X_add_number - 1;
@ -5128,17 +5192,22 @@ operand_match (idesc, index, e)
if ((val >= 0 && (bfd_vma) val < ((bfd_vma) 1 << (bits - 1)))
|| (val < 0 && (bfd_vma) -val <= ((bfd_vma) 1 << (bits - 1))))
return 1;
break;
return OPERAND_MATCH;
else
return OPERAND_OUT_OF_RANGE;
case IA64_OPND_INC3:
/* +/- 1, 4, 8, 16 */
val = e->X_add_number;
if (val < 0)
val = -val;
if (e->X_op == O_constant
&& (val == 1 || val == 4 || val == 8 || val == 16))
return 1;
if (e->X_op == O_constant)
{
if ((val == 1 || val == 4 || val == 8 || val == 16))
return OPERAND_MATCH;
else
return OPERAND_OUT_OF_RANGE;
}
break;
case IA64_OPND_TGT25:
@ -5164,14 +5233,14 @@ operand_match (idesc, index, e)
fix->expr = *e;
fix->is_pcrel = 1;
++CURR_SLOT.num_fixups;
return 1;
return OPERAND_MATCH;
}
case IA64_OPND_TAG13:
case IA64_OPND_TAG13b:
switch (e->X_op)
{
case O_constant:
return 1;
return OPERAND_MATCH;
case O_symbol:
fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
@ -5183,7 +5252,7 @@ operand_match (idesc, index, e)
fix->expr = *e;
fix->is_pcrel = 1;
++CURR_SLOT.num_fixups;
return 1;
return OPERAND_MATCH;
default:
break;
@ -5193,7 +5262,7 @@ operand_match (idesc, index, e)
default:
break;
}
return 0;
return OPERAND_MISMATCH;
}
static int
@ -5241,8 +5310,9 @@ parse_operands (idesc)
struct ia64_opcode *idesc;
{
int i = 0, highest_unmatched_operand, num_operands = 0, num_outputs = 0;
int sep = 0;
int error_pos, out_of_range_pos, curr_out_of_range_pos, sep = 0;
enum ia64_opnd expected_operand = IA64_OPND_NIL;
enum operand_match_result result;
char mnemonic[129];
char *first_arg = 0, *end, *saved_input_pointer;
unsigned int sof;
@ -5324,6 +5394,8 @@ parse_operands (idesc)
}
highest_unmatched_operand = 0;
curr_out_of_range_pos = -1;
error_pos = 0;
expected_operand = idesc->operands[0];
for (; idesc; idesc = get_next_opcode (idesc))
{
@ -5331,16 +5403,52 @@ parse_operands (idesc)
continue; /* mismatch in # of outputs */
CURR_SLOT.num_fixups = 0;
for (i = 0; i < num_operands && idesc->operands[i]; ++i)
if (!operand_match (idesc, i, CURR_SLOT.opnd + i))
break;
if (i != num_operands)
/* Try to match all operands. If we see an out-of-range operand,
then continue trying to match the rest of the operands, since if
the rest match, then this idesc will give the best error message. */
out_of_range_pos = -1;
for (i = 0; i < num_operands && idesc->operands[i]; ++i)
{
if (i > highest_unmatched_operand)
result = operand_match (idesc, i, CURR_SLOT.opnd + i);
if (result != OPERAND_MATCH)
{
if (result != OPERAND_OUT_OF_RANGE)
break;
if (out_of_range_pos < 0)
/* remember position of the first out-of-range operand: */
out_of_range_pos = i;
}
}
/* If we did not match all operands, or if at least one operand was
out-of-range, then this idesc does not match. Keep track of which
idesc matched the most operands before failing. If we have two
idescs that failed at the same position, and one had an out-of-range
operand, then prefer the out-of-range operand. Thus if we have
"add r0=0x1000000,r1" we get an error saying the constant is out
of range instead of an error saying that the constant should have been
a register. */
if (i != num_operands || out_of_range_pos >= 0)
{
if (i > highest_unmatched_operand
|| (i == highest_unmatched_operand
&& out_of_range_pos > curr_out_of_range_pos))
{
highest_unmatched_operand = i;
expected_operand = idesc->operands[i];
if (out_of_range_pos >= 0)
{
expected_operand = idesc->operands[out_of_range_pos];
error_pos = out_of_range_pos;
}
else
{
expected_operand = idesc->operands[i];
error_pos = i;
}
curr_out_of_range_pos = out_of_range_pos;
}
continue;
}
@ -5355,7 +5463,7 @@ parse_operands (idesc)
{
if (expected_operand)
as_bad ("Operand %u of `%s' should be %s",
highest_unmatched_operand + 1, mnemonic,
error_pos + 1, mnemonic,
elf64_ia64_operands[expected_operand].desc);
else
as_bad ("Operand mismatch");

View File

@ -1,3 +1,9 @@
2001-02-21 David Mosberger <davidm@hpl.hp.com>
* ia64-opc-d.c (ia64_opcodes_d): Break the "add" pattern into two
separate variants: one for IMM22 and the other for IMM14.
* ia64-asmtab.c: Regenerate.
2001-02-21 Greg McGary <greg@mcgary.org>
* cgen-opc.c (cgen_get_insn_value): Add missing `return'.

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,9 @@
struct ia64_opcode ia64_opcodes_d[] =
{
{"add", IA64_TYPE_DYN, 1, 0, 0,
{IA64_OPND_R1, IA64_OPND_IMM22, IA64_OPND_R3}},
{IA64_OPND_R1, IA64_OPND_IMM22, IA64_OPND_R3_2}},
{"add", IA64_TYPE_DYN, 1, 0, 0,
{IA64_OPND_R1, IA64_OPND_IMM14, IA64_OPND_R3}},
{"break", IA64_TYPE_DYN, 0, 0, 0, {IA64_OPND_IMMU21}},
{"chk.s", IA64_TYPE_DYN, 0, 0, 0, {IA64_OPND_R2, IA64_OPND_TGT25b}},
{"mov", IA64_TYPE_DYN, 1, 0, 0, {IA64_OPND_R1, IA64_OPND_AR3}},