/* Set to TRUE if we want to warn about zero base/index registers. */
static bool warn_areg_zero = false;
+/* Whether to warn about register name type check mismatches. */
+#ifndef S390_REGTYPE_CHECK
+#define S390_REGTYPE_CHECK S390_REGTYPE_CHECK_RELAXED
+#endif
+
+enum s390_regtype_check {
+ S390_REGTYPE_CHECK_NONE = 0, /* No register name type checks. */
+ S390_REGTYPE_CHECK_RELAXED, /* Relaxed register name type checks. */
+ S390_REGTYPE_CHECK_STRICT /* Strict register name type checks. */
+};
+
+/* Whether to warn about register name type check mismatches. */
+static enum s390_regtype_check warn_regtype_mismatch = S390_REGTYPE_CHECK;
+
/* Generic assembler global variables which must be defined by all
targets. */
{ NULL, NULL, 0 }
};
+/* Register types. */
+enum s390_register_type
+ {
+ S390_REGTYPE_AR, /* Access register. */
+ S390_REGTYPE_CR, /* Control register. */
+ S390_REGTYPE_FPR, /* Floating-point register. */
+ S390_REGTYPE_GR, /* General register. */
+ S390_REGTYPE_VR, /* Vector register. */
+ };
+
/* Given NAME, find the register number associated with that name, return
the integer value associated with the given name or -1 on failure. */
{
expressionP->X_op = O_register;
expressionP->X_add_number = reg_number;
+ switch (name[0])
+ {
+ case 'a':
+ expressionP->X_md = S390_REGTYPE_AR;
+ break;
+ case 'c':
+ expressionP->X_md = S390_REGTYPE_CR;
+ break;
+ case 'f':
+ expressionP->X_md = S390_REGTYPE_FPR;
+ break;
+ case 'r':
+ expressionP->X_md = S390_REGTYPE_GR;
+ break;
+ case 'v':
+ expressionP->X_md = S390_REGTYPE_VR;
+ break;
+ default:
+ expressionP->X_md = 0;
+ }
/* Make the rest nice. */
expressionP->X_add_symbol = NULL;
else if (arg != NULL && strcmp (arg, "warn-areg-zero") == 0)
warn_areg_zero = true;
+ else if (arg != NULL && strcmp (arg, "warn-regtype-mismatch=strict") == 0)
+ warn_regtype_mismatch = S390_REGTYPE_CHECK_STRICT;
+
+ else if (arg != NULL && strcmp (arg, "warn-regtype-mismatch=relaxed") == 0)
+ warn_regtype_mismatch = S390_REGTYPE_CHECK_RELAXED;
+
+ else if (arg != NULL && strcmp (arg, "warn-regtype-mismatch=no") == 0)
+ warn_regtype_mismatch = S390_REGTYPE_CHECK_NONE;
+
+ else if (arg != NULL && strcmp (arg, "no-warn-regtype-mismatch") == 0)
+ warn_regtype_mismatch = S390_REGTYPE_CHECK_NONE;
+
else if (arg != NULL && strcmp (arg, "31") == 0)
s390_arch_size = 32;
-mregnames allow symbolic names for registers\n\
-mno-regnames do not allow symbolic names for registers\n\
-mwarn-areg-zero warn about base/index register zero\n\
+ -mwarn-regtype-mismatch=strict\n\
+ warn about register name type mismatches\n\
+ -mwarn-regtype-mismatch=relaxed\n\
+ warn about register name type mismatches,\n\
+ but allow FPR and VR to be used interchangeably\n\
+ -mno-warn-regtype-mismatch\n\
+ do not warn about register name type mismatches\n\
"));
fprintf (stream, _("\
-V print assembler version number\n\
elf_suffix_type suffix;
bfd_reloc_code_real_type reloc;
int omitted_base_or_index;
+ int operand_number;
char *f;
int fc, i;
/* Gather the operands. */
omitted_base_or_index = 0; /* Whether B in D(L,B) or X in D(X,B) were omitted. */
+ operand_number = 1; /* Current operand number in e.g. R1,I2,M3,D4(B4). */
fc = 0;
for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
{
as_bad (_("invalid floating point register pair. Valid fp "
"register pair operands are 0, 1, 4, 5, 8, 9, "
"12 or 13."));
+ if (warn_regtype_mismatch && ex.X_op == O_register
+ && !(opcode->flags & S390_INSTR_FLAG_PSEUDO_MNEMONIC))
+ {
+ const char *expected_regtype = NULL;
+
+ if ((operand->flags & S390_OPERAND_AR)
+ && ex.X_md != S390_REGTYPE_AR)
+ expected_regtype = _("access register");
+ else if ((operand->flags & S390_OPERAND_CR)
+ && ex.X_md != S390_REGTYPE_CR)
+ expected_regtype = _("control register");
+ else if ((operand->flags & S390_OPERAND_FPR)
+ && ex.X_md != S390_REGTYPE_FPR
+ && (warn_regtype_mismatch == S390_REGTYPE_CHECK_STRICT
+ || (ex.X_md != S390_REGTYPE_VR)))
+ expected_regtype = _("floating-point register");
+ else if ((operand->flags & S390_OPERAND_GPR)
+ && ex.X_md != S390_REGTYPE_GR)
+ expected_regtype = _("general register");
+ else if ((operand->flags & S390_OPERAND_VR)
+ && ex.X_md != S390_REGTYPE_VR
+ && (warn_regtype_mismatch == S390_REGTYPE_CHECK_STRICT
+ || (ex.X_md != S390_REGTYPE_FPR)))
+ expected_regtype = _("vector register");
+
+ if (expected_regtype)
+ {
+ if (operand->flags & S390_OPERAND_BASE)
+ as_warn (_("operand %d: expected %s name as base register"),
+ operand_number, expected_regtype);
+ else if (operand->flags & S390_OPERAND_INDEX)
+ as_warn (_("operand %d: expected %s name as index register"),
+ operand_number, expected_regtype);
+ else
+ as_warn (_("operand %d: expected %s name"),
+ operand_number, expected_regtype);
+ }
+ }
s390_insert_operand (insn, operand, ex.X_add_number, NULL, 0);
}
}
{
/* Comma. */
str++;
+ operand_number++;
}
}
}
{
/* Comma. */
str++;
+ operand_number++;
}
}
}
{
/* Comma. */
str++;
+ if (!(operand->flags & (S390_OPERAND_INDEX
+ | S390_OPERAND_LENGTH)))
+ operand_number++;
}
}
}
const struct s390_opcode s390_opformats[] =
{
- { "e", OP8(0x00LL), MASK_E, INSTR_E, 3, 0, 0, NULL },
- { "ri", OP8(0x00LL), MASK_RI_RI, INSTR_RI_RI, 3, 0, 0, NULL },
- { "rie", OP8(0x00LL), MASK_RIE_RRP, INSTR_RIE_RRP, 3, 0, 0, NULL },
- { "ril", OP8(0x00LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 0, 0, NULL },
- { "rilu", OP8(0x00LL), MASK_RIL_RU, INSTR_RIL_RU, 3, 0, 0, NULL },
- { "ris", OP8(0x00LL), MASK_RIS_RURDI, INSTR_RIS_RURDI, 3, 6, 0, NULL },
- { "rr", OP8(0x00LL), MASK_RR_RR, INSTR_RR_RR, 3, 0, 0, NULL },
- { "rre", OP8(0x00LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0, 0, NULL },
- { "rrf", OP8(0x00LL), MASK_RRF_RURR, INSTR_RRF_RURR, 3, 0, 0, NULL },
- { "rrs", OP8(0x00LL), MASK_RRS_RRRDU, INSTR_RRS_RRRDU, 3, 6, 0, NULL },
- { "rs", OP8(0x00LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0, 0, NULL },
- { "rse", OP8(0x00LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0, 0, NULL },
- { "rsi", OP8(0x00LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0, 0, NULL },
- { "rsy", OP8(0x00LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3, 0, NULL },
- { "rx", OP8(0x00LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0, 0, NULL },
- { "rxe", OP8(0x00LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 0, 0, NULL },
- { "rxf", OP8(0x00LL), MASK_RXF_RRRDR, INSTR_RXF_RRRDR, 3, 0, 0, NULL },
- { "rxy", OP8(0x00LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3, 0, NULL },
- { "s", OP8(0x00LL), MASK_S_RD, INSTR_S_RD, 3, 0, 0, NULL },
- { "si", OP8(0x00LL), MASK_SI_URD, INSTR_SI_URD, 3, 0, 0, NULL },
- { "siy", OP8(0x00LL), MASK_SIY_URD, INSTR_SIY_URD, 3, 3, 0, NULL },
- { "sil", OP8(0x00LL), MASK_SIL_RDI, INSTR_SIL_RDI, 3, 6, 0, NULL },
- { "ss", OP8(0x00LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0, 0, NULL },
- { "sse", OP8(0x00LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0, 0, NULL },
- { "ssf", OP8(0x00LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 3, 0, 0, NULL },
- { "vrv", OP8(0x00LL), MASK_VRV_VVXRDU, INSTR_VRV_VVXRDU, 3, 9, 0, NULL },
- { "vri", OP8(0x00LL), MASK_VRI_VVUUU, INSTR_VRI_VVUUU, 3, 9, 0, NULL },
- { "vrx", OP8(0x00LL), MASK_VRX_VRRDU, INSTR_VRX_VRRDU, 3, 9, 0, NULL },
- { "vrs", OP8(0x00LL), MASK_VRS_RVRDU, INSTR_VRS_RVRDU, 3, 9, 0, NULL },
- { "vrr", OP8(0x00LL), MASK_VRR_VVV0UUU, INSTR_VRR_VVV0UUU, 3, 9, 0, NULL },
- { "vsi", OP8(0x00LL), MASK_VSI_URDV, INSTR_VSI_URDV, 3, 10, 0, NULL },
+ { "e", OP8(0x00LL), MASK_E, INSTR_E, 3, 0, 256, NULL },
+ { "ri", OP8(0x00LL), MASK_RI_RI, INSTR_RI_RI, 3, 0, 256, NULL },
+ { "rie", OP8(0x00LL), MASK_RIE_RRP, INSTR_RIE_RRP, 3, 0, 256, NULL },
+ { "ril", OP8(0x00LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 0, 256, NULL },
+ { "rilu", OP8(0x00LL), MASK_RIL_RU, INSTR_RIL_RU, 3, 0, 256, NULL },
+ { "ris", OP8(0x00LL), MASK_RIS_RURDI, INSTR_RIS_RURDI, 3, 6, 256, NULL },
+ { "rr", OP8(0x00LL), MASK_RR_RR, INSTR_RR_RR, 3, 0, 256, NULL },
+ { "rre", OP8(0x00LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0, 256, NULL },
+ { "rrf", OP8(0x00LL), MASK_RRF_RURR, INSTR_RRF_RURR, 3, 0, 256, NULL },
+ { "rrs", OP8(0x00LL), MASK_RRS_RRRDU, INSTR_RRS_RRRDU, 3, 6, 256, NULL },
+ { "rs", OP8(0x00LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0, 256, NULL },
+ { "rse", OP8(0x00LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0, 256, NULL },
+ { "rsi", OP8(0x00LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0, 256, NULL },
+ { "rsy", OP8(0x00LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3, 256, NULL },
+ { "rx", OP8(0x00LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0, 256, NULL },
+ { "rxe", OP8(0x00LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 0, 256, NULL },
+ { "rxf", OP8(0x00LL), MASK_RXF_RRRDR, INSTR_RXF_RRRDR, 3, 0, 256, NULL },
+ { "rxy", OP8(0x00LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3, 256, NULL },
+ { "s", OP8(0x00LL), MASK_S_RD, INSTR_S_RD, 3, 0, 256, NULL },
+ { "si", OP8(0x00LL), MASK_SI_URD, INSTR_SI_URD, 3, 0, 256, NULL },
+ { "siy", OP8(0x00LL), MASK_SIY_URD, INSTR_SIY_URD, 3, 3, 256, NULL },
+ { "sil", OP8(0x00LL), MASK_SIL_RDI, INSTR_SIL_RDI, 3, 6, 256, NULL },
+ { "ss", OP8(0x00LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0, 256, NULL },
+ { "sse", OP8(0x00LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0, 256, NULL },
+ { "ssf", OP8(0x00LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 3, 0, 256, NULL },
+ { "vrv", OP8(0x00LL), MASK_VRV_VVXRDU, INSTR_VRV_VVXRDU, 3, 9, 256, NULL },
+ { "vri", OP8(0x00LL), MASK_VRI_VVUUU, INSTR_VRI_VVUUU, 3, 9, 256, NULL },
+ { "vrx", OP8(0x00LL), MASK_VRX_VRRDU, INSTR_VRX_VRRDU, 3, 9, 256, NULL },
+ { "vrs", OP8(0x00LL), MASK_VRS_RVRDU, INSTR_VRS_RVRDU, 3, 9, 256, NULL },
+ { "vrr", OP8(0x00LL), MASK_VRR_VVV0UUU, INSTR_VRR_VVV0UUU, 3, 9, 256, NULL },
+ { "vsi", OP8(0x00LL), MASK_VSI_URDV, INSTR_VSI_URDV, 3, 10, 256, NULL },
};
const int s390_num_opformats =