break;
/* Generate the operand string in STR. */
- aarch64_print_operand (str, sizeof (str), 0, opcode, opnds, i, NULL, NULL);
+ aarch64_print_operand (str, sizeof (str), 0, opcode, opnds, i, NULL, NULL,
+ NULL);
/* Delimiter. */
if (str[0] != '\0')
enum aarch64_opnd opd_code = (idx >= 0 ? opcode->operands[idx]
: AARCH64_OPND_NIL);
+ typedef void (*handler_t)(const char *format, ...);
+ handler_t handler = detail->non_fatal ? as_warn : as_bad;
+
switch (detail->kind)
{
case AARCH64_OPDE_NIL:
gas_assert (0);
break;
-
case AARCH64_OPDE_SYNTAX_ERROR:
case AARCH64_OPDE_RECOVERABLE:
case AARCH64_OPDE_FATAL_SYNTAX_ERROR:
if (detail->error != NULL)
{
if (idx < 0)
- as_bad (_("%s -- `%s'"), detail->error, str);
+ handler (_("%s -- `%s'"), detail->error, str);
else
- as_bad (_("%s at operand %d -- `%s'"),
- detail->error, idx + 1, str);
+ handler (_("%s at operand %d -- `%s'"),
+ detail->error, idx + 1, str);
}
else
{
gas_assert (idx >= 0);
- as_bad (_("operand %d must be %s -- `%s'"), idx + 1,
- aarch64_get_operand_desc (opd_code), str);
+ handler (_("operand %d must be %s -- `%s'"), idx + 1,
+ aarch64_get_operand_desc (opd_code), str);
}
break;
case AARCH64_OPDE_INVALID_VARIANT:
- as_bad (_("operand mismatch -- `%s'"), str);
+ handler (_("operand mismatch -- `%s'"), str);
if (verbose_error_p)
{
/* We will try to correct the erroneous instruction and also provide
break;
case AARCH64_OPDE_UNTIED_OPERAND:
- as_bad (_("operand %d must be the same register as operand 1 -- `%s'"),
- detail->index + 1, str);
+ handler (_("operand %d must be the same register as operand 1 -- `%s'"),
+ detail->index + 1, str);
break;
case AARCH64_OPDE_OUT_OF_RANGE:
if (detail->data[0] != detail->data[1])
- as_bad (_("%s out of range %d to %d at operand %d -- `%s'"),
- detail->error ? detail->error : _("immediate value"),
- detail->data[0], detail->data[1], idx + 1, str);
+ handler (_("%s out of range %d to %d at operand %d -- `%s'"),
+ detail->error ? detail->error : _("immediate value"),
+ detail->data[0], detail->data[1], idx + 1, str);
else
- as_bad (_("%s must be %d at operand %d -- `%s'"),
- detail->error ? detail->error : _("immediate value"),
- detail->data[0], idx + 1, str);
+ handler (_("%s must be %d at operand %d -- `%s'"),
+ detail->error ? detail->error : _("immediate value"),
+ detail->data[0], idx + 1, str);
break;
case AARCH64_OPDE_REG_LIST:
if (detail->data[0] == 1)
- as_bad (_("invalid number of registers in the list; "
- "only 1 register is expected at operand %d -- `%s'"),
- idx + 1, str);
+ handler (_("invalid number of registers in the list; "
+ "only 1 register is expected at operand %d -- `%s'"),
+ idx + 1, str);
else
- as_bad (_("invalid number of registers in the list; "
- "%d registers are expected at operand %d -- `%s'"),
- detail->data[0], idx + 1, str);
+ handler (_("invalid number of registers in the list; "
+ "%d registers are expected at operand %d -- `%s'"),
+ detail->data[0], idx + 1, str);
break;
case AARCH64_OPDE_UNALIGNED:
- as_bad (_("immediate value must be a multiple of "
- "%d at operand %d -- `%s'"),
- detail->data[0], idx + 1, str);
+ handler (_("immediate value must be a multiple of "
+ "%d at operand %d -- `%s'"),
+ detail->data[0], idx + 1, str);
break;
default:
When this function is called, the operand error information had
been collected for an assembly line and there will be multiple
errors in the case of multiple instruction templates; output the
- error message that most closely describes the problem. */
+ error message that most closely describes the problem.
+
+ The errors to be printed can be filtered on printing all errors
+ or only non-fatal errors. This distinction has to be made because
+ the error buffer may already be filled with fatal errors we don't want to
+ print due to the different instruction templates. */
static void
-output_operand_error_report (char *str)
+output_operand_error_report (char *str, bfd_boolean non_fatal_only)
{
int largest_error_pos;
const char *msg = NULL;
/* Only one error. */
if (head == operand_error_report.tail)
{
- DEBUG_TRACE ("single opcode entry with error kind: %s",
- operand_mismatch_kind_names[head->detail.kind]);
- output_operand_error_record (head, str);
+ /* If the only error is a non-fatal one and we don't want to print it,
+ just exit. */
+ if (!non_fatal_only || head->detail.non_fatal)
+ {
+ DEBUG_TRACE ("single opcode entry with error kind: %s",
+ operand_mismatch_kind_names[head->detail.kind]);
+ output_operand_error_record (head, str);
+ }
return;
}
largest_error_pos = -2; /* Index can be -1 which means unknown index. */
for (curr = head; curr != NULL; curr = curr->next)
{
- if (curr->detail.kind != kind)
+ /* If we don't want to print non-fatal errors then don't consider them
+ at all. */
+ if (curr->detail.kind != kind
+ || (non_fatal_only && !head->detail.non_fatal))
continue;
/* If there are multiple errors, pick up the one with the highest
mismatching operand index. In the case of multiple errors with
}
}
+ /* The way errors are collected in the back-end is a bit non-intuitive. But
+ essentially, because each operand template is tried recursively you may
+ always have errors collected from the previous tried OPND. These are
+ usually skipped if there is one successful match. However now with the
+ non-fatal errors we have to ignore those previously collected hard errors
+ when we're only interested in printing the non-fatal ones. This condition
+ prevents us from printing errors that are not appropriate, since we did
+ match a condition, but it also has warnings that it wants to print. */
+ if (non_fatal_only && !record)
+ return;
+
gas_assert (largest_error_pos != -2 && record != NULL);
DEBUG_TRACE ("Pick up error kind %s to report",
operand_mismatch_kind_names[record->detail.kind]);
goto regoff_addr;
case AARCH64_OPND_SYSREG:
- {
- uint32_t sysreg_flags;
- if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0,
- &sysreg_flags)) == PARSE_FAIL)
- {
- set_syntax_error (_("unknown or missing system register name"));
- goto failure;
- }
- inst.base.operands[i].sysreg.value = val;
- inst.base.operands[i].sysreg.flags = sysreg_flags;
- break;
- }
+ {
+ uint32_t sysreg_flags;
+ if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0,
+ &sysreg_flags)) == PARSE_FAIL)
+ {
+ set_syntax_error (_("unknown or missing system register name"));
+ goto failure;
+ }
+ inst.base.operands[i].sysreg.value = val;
+ inst.base.operands[i].sysreg.flags = sysreg_flags;
+ break;
+ }
case AARCH64_OPND_PSTATEFIELD:
if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0, 1, NULL))
aarch64_insn *code)
{
aarch64_operand_error error_info;
+ memset (&error_info, '\0', sizeof (error_info));
error_info.kind = AARCH64_OPDE_NIL;
- if (aarch64_opcode_encode (opcode, instr, code, NULL, &error_info))
+ if (aarch64_opcode_encode (opcode, instr, code, NULL, &error_info)
+ && !error_info.non_fatal)
return TRUE;
- else
- {
- gas_assert (error_info.kind != AARCH64_OPDE_NIL);
- record_operand_error_info (opcode, &error_info);
- return FALSE;
- }
+
+ gas_assert (error_info.kind != AARCH64_OPDE_NIL);
+ record_operand_error_info (opcode, &error_info);
+ return error_info.non_fatal;
}
#ifdef DEBUG_AARCH64
memcpy (copy, &inst.base, sizeof (struct aarch64_inst));
output_inst (copy);
}
+
+ /* Issue non-fatal messages if any. */
+ output_operand_error_report (str, TRUE);
return;
}
while (template != NULL);
/* Issue the error messages if any. */
- output_operand_error_report (str);
+ output_operand_error_report (str, FALSE);
}
/* Various frobbings of labels and their addresses. */