aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-ia64.c
diff options
context:
space:
mode:
authorJim Wilson <wilson@tuliptree.org>2001-02-22 03:16:21 +0000
committerJim Wilson <wilson@tuliptree.org>2001-02-22 03:16:21 +0000
commit87f8eb977e936160d4c332d88a8bce3db690521c (patch)
tree1fa8f38d53a0c82edb0d50d47e634702cc3a6b6c /gas/config/tc-ia64.c
parentaacc1edd3ae439544e7e1e2e03ff456b723eae02 (diff)
downloadgdb-87f8eb977e936160d4c332d88a8bce3db690521c.zip
gdb-87f8eb977e936160d4c332d88a8bce3db690521c.tar.gz
gdb-87f8eb977e936160d4c332d88a8bce3db690521c.tar.bz2
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.
Diffstat (limited to 'gas/config/tc-ia64.c')
-rw-r--r--gas/config/tc-ia64.c306
1 files changed, 207 insertions, 99 deletions
diff --git a/gas/config/tc-ia64.c b/gas/config/tc-ia64.c
index 56f80d9..517d96c 100644
--- a/gas/config/tc-ia64.c
+++ b/gas/config/tc-ia64.c
@@ -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))))
- {
- /* sign-extend */
- if (e->X_add_number >= 0
- && (e->X_add_number & ((bfd_vma) 1 << 16)) != 0)
+ if (e->X_op == O_constant)
+ {
+ 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;
+
+ /* 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 (!operand_match (idesc, i, CURR_SLOT.opnd + i))
- break;
+ {
+ 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)
+ if (i != num_operands || out_of_range_pos >= 0)
{
- if (i > highest_unmatched_operand)
+ 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");