This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Thumb32 assembler (7/69)


Restructure of the register parsers.  All the tables are folded
together, and the register category made part of the information that
the entry carries.  This facilitates later changes that want to refer
to register categories by code number.  Also, the static table
migrates down near its sole user, reducing the clutter at the top of
the file.

Two things to note about this patch: I removed the ability to delete
standard register names with .unreq, as this caused memory leakage and
seemed a dubious feature anyway.  Also, I'm not 100% sure the handling
of the iwmmxt register set is correct.  I found one bug dozens of
patches later, and there may be others.

zw

	* config/tc-arm.c (IWMMXT_REG_WR_OR_WC, wr_register, wc_register)
	(wcg_register, rn_table, WR_PREFIX, WC_PREFIX, iwmmxt_table, cp_table)
	(cn_table, fn_table, sn_table, dn_table, mav_mvf_table, mav_mvd_table)
	(mav_mvfx_table, mav_mvdx_table, mav_mvax_table, mav_dspsc_table)
	(reg_map, all_reg_maps, REG_TYPE_FIRST, REG_TYPE_IWMMXT, REG_TYPE_MAX)
	(BAD_ACCUM, arm_reg_parse_any, insert_reg, build_reg_hsh): Delete.
	(struct reg_entry): Add type field.
	(reg_expected_msgs, reg_names): New table.
	(REG_TYPE_MMXWR, REG_TYPE_MMXWC, REG_TYPE_MMXWCG, REG_TYPE_XSCALE):
	New arm_reg_type enumerators.
	(arm_reg_hsh): New file-static variable.
	(arm_ops_hsh, arm_tops_hsh, arm_cond_hsh, arm_shift_hsh, arm_psr_hsh):
	Remove unnecessary initializers.
	(arm_reg_parse): Take a type code, not a hashtable.  Use arm_reg_hsh.
	(vfp_dp_encode_reg): Split out of vfp_dp_reg_required_here.
	(reg_required_here, vfp_sp_reg_required_here, vfp_dp_reg_required_here)
	(fp_reg_required_here, cp_reg_required_here, wreg_required_here)
	(mav_reg_required_here, xsc_reg_required_here, vfp_parse_reg_list)
	(co_proc_number, s_arm_unwind_save, tc_arm_regname_to_dw2regnum):
	Update to changed arm_reg_parse	interface.
	(insert_reg_alias, create_register_alias, s_unreq): Rewrite for unified
	register table.  Do not allow modification or deletion of standard
	registers.
	(s_arm_unwind_save_wmmx): Split into s_arm_unwind_save_mmxwr and
	s_arm_unwind_save_mmxwcg.
	(do_iwmmxt_byte_addr): Disallow WC registers during parsing, not
	during encoding.
	(do_iwmmxt_word_addr): Check separately for WR and WC registers.
	(md_begin): Initialize arm_reg_hsh.
	* testsuite/gas/arm/req.l: Update expected diagnostics.
	* testsuite/gas/arm/req.s: Adjust commentary.

===================================================================
Index: gas/testsuite/gas/arm/req.l
--- gas/testsuite/gas/arm/req.l	(revision 8)
+++ gas/testsuite/gas/arm/req.l	(revision 9)
@@ -1,3 +1,3 @@
 [^:]*: Assembler messages:
-[^:]*:18: Error: register expected, not 'foo,foo,foo' -- `add foo,foo,foo'
-[^:]*:24: Error: register expected, not 'r0,r0,r0' -- `add r0,r0,r0'
+[^:]*:18: Error: ARM register expected -- `add foo,foo,foo'
+[^:]*:21: Warning: ignoring attempt to undefine built-in register 'r0'
===================================================================
Index: gas/testsuite/gas/arm/req.s
--- gas/testsuite/gas/arm/req.s	(revision 8)
+++ gas/testsuite/gas/arm/req.s	(revision 9)
@@ -2,7 +2,7 @@
 	.global test_dot_req_and_unreq
 test_dot_req_and_unreq:
 
-	#  Check that builtin register alias 'r0' works.
+	# Check that builtin register alias 'r0' works.
 	add r0, r0, r0
 
 	# Create an alias for r0.
@@ -17,9 +17,9 @@
 	# And make sure that it no longer works.
 	add foo, foo, foo
 
-	# Finally remove the builtin alias for r0.
+	# Attempt to remove the builtin alias for r0.
         .unreq r0
 
-	# And make sure that this no longer works.
+	# That is ignored, so this should still work.
 	add r0, r0, r0
 	
===================================================================
Index: gas/config/tc-arm.c
--- gas/config/tc-arm.c	(revision 8)
+++ gas/config/tc-arm.c	(revision 9)
@@ -485,7 +485,6 @@
   {
     IWMMXT_REG_WR = 0,
     IWMMXT_REG_WC = 1,
-    IWMMXT_REG_WR_OR_WC = 2,
     IWMMXT_REG_WCG
   };
 
@@ -542,213 +541,11 @@
   {"FPEXC", 0x00080000}
 };
 
-/* Structure for a hash table entry for a register.  */
-struct reg_entry
-{
-  const char * name;
-  int          number;
-  bfd_boolean  builtin;
-};
-
-/* Some well known registers that we refer to directly elsewhere.  */
-#define REG_SP  13
-#define REG_LR  14
-#define REG_PC	15
-
-#define wr_register(reg)  ((reg ^ WR_PREFIX) >= 0 && (reg ^ WR_PREFIX) <= 15)
-#define wc_register(reg)  ((reg ^ WC_PREFIX) >= 0 && (reg ^ WC_PREFIX) <= 15)
-#define wcg_register(reg) ((reg ^ WC_PREFIX) >= 8 && (reg ^ WC_PREFIX) <= 11)
-
-/* These are the standard names.  Users can add aliases with .req.
-   and delete them with .unreq.  */
-
-/* Integer Register Numbers.  */
-static const struct reg_entry rn_table[] =
-{
-  {"r0",  0, TRUE},  {"r1",  1, TRUE},      {"r2",  2, TRUE},      {"r3",  3, TRUE},
-  {"r4",  4, TRUE},  {"r5",  5, TRUE},      {"r6",  6, TRUE},      {"r7",  7, TRUE},
-  {"r8",  8, TRUE},  {"r9",  9, TRUE},      {"r10", 10, TRUE},     {"r11", 11, TRUE},
-  {"r12", 12, TRUE}, {"r13", REG_SP, TRUE}, {"r14", REG_LR, TRUE}, {"r15", REG_PC, TRUE},
-  /* ATPCS Synonyms.  */
-  {"a1",  0, TRUE},  {"a2",  1, TRUE},      {"a3",  2, TRUE},      {"a4",  3, TRUE},
-  {"v1",  4, TRUE},  {"v2",  5, TRUE},      {"v3",  6, TRUE},      {"v4",  7, TRUE},
-  {"v5",  8, TRUE},  {"v6",  9, TRUE},      {"v7",  10, TRUE},     {"v8",  11, TRUE},
-  /* Well-known aliases.  */
-  {"wr",  7, TRUE},  {"sb",  9, TRUE},      {"sl",  10, TRUE},     {"fp",  11, TRUE},
-  {"ip",  12, TRUE}, {"sp",  REG_SP, TRUE}, {"lr",  REG_LR, TRUE}, {"pc",  REG_PC, TRUE},
-  {NULL, 0, TRUE}
-};
-
-#define WR_PREFIX 0x200
-#define WC_PREFIX 0x400
-
-static const struct reg_entry iwmmxt_table[] =
-{
-  /* Intel Wireless MMX technology register names.  */
-  {  "wr0", 0x0 | WR_PREFIX, TRUE},   {"wr1", 0x1 | WR_PREFIX, TRUE},
-  {  "wr2", 0x2 | WR_PREFIX, TRUE},   {"wr3", 0x3 | WR_PREFIX, TRUE},
-  {  "wr4", 0x4 | WR_PREFIX, TRUE},   {"wr5", 0x5 | WR_PREFIX, TRUE},
-  {  "wr6", 0x6 | WR_PREFIX, TRUE},   {"wr7", 0x7 | WR_PREFIX, TRUE},
-  {  "wr8", 0x8 | WR_PREFIX, TRUE},   {"wr9", 0x9 | WR_PREFIX, TRUE},
-  { "wr10", 0xa | WR_PREFIX, TRUE},  {"wr11", 0xb | WR_PREFIX, TRUE},
-  { "wr12", 0xc | WR_PREFIX, TRUE},  {"wr13", 0xd | WR_PREFIX, TRUE},
-  { "wr14", 0xe | WR_PREFIX, TRUE},  {"wr15", 0xf | WR_PREFIX, TRUE},
-  { "wcid", 0x0 | WC_PREFIX, TRUE},  {"wcon", 0x1 | WC_PREFIX, TRUE},
-  {"wcssf", 0x2 | WC_PREFIX, TRUE}, {"wcasf", 0x3 | WC_PREFIX, TRUE},
-  {"wcgr0", 0x8 | WC_PREFIX, TRUE}, {"wcgr1", 0x9 | WC_PREFIX, TRUE},
-  {"wcgr2", 0xa | WC_PREFIX, TRUE}, {"wcgr3", 0xb | WC_PREFIX, TRUE},
-
-  {  "wR0", 0x0 | WR_PREFIX, TRUE},   {"wR1", 0x1 | WR_PREFIX, TRUE},
-  {  "wR2", 0x2 | WR_PREFIX, TRUE},   {"wR3", 0x3 | WR_PREFIX, TRUE},
-  {  "wR4", 0x4 | WR_PREFIX, TRUE},   {"wR5", 0x5 | WR_PREFIX, TRUE},
-  {  "wR6", 0x6 | WR_PREFIX, TRUE},   {"wR7", 0x7 | WR_PREFIX, TRUE},
-  {  "wR8", 0x8 | WR_PREFIX, TRUE},   {"wR9", 0x9 | WR_PREFIX, TRUE},
-  { "wR10", 0xa | WR_PREFIX, TRUE},  {"wR11", 0xb | WR_PREFIX, TRUE},
-  { "wR12", 0xc | WR_PREFIX, TRUE},  {"wR13", 0xd | WR_PREFIX, TRUE},
-  { "wR14", 0xe | WR_PREFIX, TRUE},  {"wR15", 0xf | WR_PREFIX, TRUE},
-  { "wCID", 0x0 | WC_PREFIX, TRUE},  {"wCon", 0x1 | WC_PREFIX, TRUE},
-  {"wCSSF", 0x2 | WC_PREFIX, TRUE}, {"wCASF", 0x3 | WC_PREFIX, TRUE},
-  {"wCGR0", 0x8 | WC_PREFIX, TRUE}, {"wCGR1", 0x9 | WC_PREFIX, TRUE},
-  {"wCGR2", 0xa | WC_PREFIX, TRUE}, {"wCGR3", 0xb | WC_PREFIX, TRUE},
-  {NULL, 0, TRUE}
-};
-
-/* Co-processor Numbers.  */
-static const struct reg_entry cp_table[] =
-{
-  {"p0",  0, TRUE},  {"p1",  1, TRUE},  {"p2",  2, TRUE},  {"p3", 3, TRUE},
-  {"p4",  4, TRUE},  {"p5",  5, TRUE},  {"p6",  6, TRUE},  {"p7", 7, TRUE},
-  {"p8",  8, TRUE},  {"p9",  9, TRUE},  {"p10", 10, TRUE}, {"p11", 11, TRUE},
-  {"p12", 12, TRUE}, {"p13", 13, TRUE}, {"p14", 14, TRUE}, {"p15", 15, TRUE},
-  {NULL, 0, TRUE}
-};
-
-/* Co-processor Register Numbers.  */
-static const struct reg_entry cn_table[] =
-{
-  {"c0",   0, TRUE},  {"c1",   1, TRUE},  {"c2",   2, TRUE},  {"c3",   3, TRUE},
-  {"c4",   4, TRUE},  {"c5",   5, TRUE},  {"c6",   6, TRUE},  {"c7",   7, TRUE},
-  {"c8",   8, TRUE},  {"c9",   9, TRUE},  {"c10",  10, TRUE}, {"c11",  11, TRUE},
-  {"c12",  12, TRUE}, {"c13",  13, TRUE}, {"c14",  14, TRUE}, {"c15",  15, TRUE},
-  /* Not really valid, but kept for back-wards compatibility.  */
-  {"cr0",  0, TRUE},  {"cr1",  1, TRUE},  {"cr2",  2, TRUE},  {"cr3",  3, TRUE},
-  {"cr4",  4, TRUE},  {"cr5",  5, TRUE},  {"cr6",  6, TRUE},  {"cr7",  7, TRUE},
-  {"cr8",  8, TRUE},  {"cr9",  9, TRUE},  {"cr10", 10, TRUE}, {"cr11", 11, TRUE},
-  {"cr12", 12, TRUE}, {"cr13", 13, TRUE}, {"cr14", 14, TRUE}, {"cr15", 15, TRUE},
-  {NULL, 0, TRUE}
-};
-
-/* FPA Registers.  */
-static const struct reg_entry fn_table[] =
-{
-  {"f0", 0, TRUE},   {"f1", 1, TRUE},   {"f2", 2, TRUE},   {"f3", 3, TRUE},
-  {"f4", 4, TRUE},   {"f5", 5, TRUE},   {"f6", 6, TRUE},   {"f7", 7, TRUE},
-  {NULL, 0, TRUE}
-};
-
-/* VFP SP Registers.  */
-static const struct reg_entry sn_table[] =
-{
-  {"s0",  0, TRUE},  {"s1",  1, TRUE},  {"s2",  2, TRUE},  {"s3", 3, TRUE},
-  {"s4",  4, TRUE},  {"s5",  5, TRUE},  {"s6",  6, TRUE},  {"s7", 7, TRUE},
-  {"s8",  8, TRUE},  {"s9",  9, TRUE},  {"s10", 10, TRUE}, {"s11", 11, TRUE},
-  {"s12", 12, TRUE}, {"s13", 13, TRUE}, {"s14", 14, TRUE}, {"s15", 15, TRUE},
-  {"s16", 16, TRUE}, {"s17", 17, TRUE}, {"s18", 18, TRUE}, {"s19", 19, TRUE},
-  {"s20", 20, TRUE}, {"s21", 21, TRUE}, {"s22", 22, TRUE}, {"s23", 23, TRUE},
-  {"s24", 24, TRUE}, {"s25", 25, TRUE}, {"s26", 26, TRUE}, {"s27", 27, TRUE},
-  {"s28", 28, TRUE}, {"s29", 29, TRUE}, {"s30", 30, TRUE}, {"s31", 31, TRUE},
-  {NULL, 0, TRUE}
-};
-
-/* VFP DP Registers.  */
-static const struct reg_entry dn_table[] =
-{
-  {"d0",  0, TRUE},  {"d1",  1, TRUE},  {"d2",  2, TRUE},  {"d3", 3, TRUE},
-  {"d4",  4, TRUE},  {"d5",  5, TRUE},  {"d6",  6, TRUE},  {"d7", 7, TRUE},
-  {"d8",  8, TRUE},  {"d9",  9, TRUE},  {"d10", 10, TRUE}, {"d11", 11, TRUE},
-  {"d12", 12, TRUE}, {"d13", 13, TRUE}, {"d14", 14, TRUE}, {"d15", 15, TRUE},
-  {NULL, 0, TRUE}
-};
-
-/* Maverick DSP coprocessor registers.  */
-static const struct reg_entry mav_mvf_table[] =
-{
-  {"mvf0",  0, TRUE},  {"mvf1",  1, TRUE},  {"mvf2",  2, TRUE},  {"mvf3",  3, TRUE},
-  {"mvf4",  4, TRUE},  {"mvf5",  5, TRUE},  {"mvf6",  6, TRUE},  {"mvf7",  7, TRUE},
-  {"mvf8",  8, TRUE},  {"mvf9",  9, TRUE},  {"mvf10", 10, TRUE}, {"mvf11", 11, TRUE},
-  {"mvf12", 12, TRUE}, {"mvf13", 13, TRUE}, {"mvf14", 14, TRUE}, {"mvf15", 15, TRUE},
-  {NULL, 0, TRUE}
-};
-
-static const struct reg_entry mav_mvd_table[] =
-{
-  {"mvd0",  0, TRUE},  {"mvd1",  1, TRUE},  {"mvd2",  2, TRUE},  {"mvd3",  3, TRUE},
-  {"mvd4",  4, TRUE},  {"mvd5",  5, TRUE},  {"mvd6",  6, TRUE},  {"mvd7",  7, TRUE},
-  {"mvd8",  8, TRUE},  {"mvd9",  9, TRUE},  {"mvd10", 10, TRUE}, {"mvd11", 11, TRUE},
-  {"mvd12", 12, TRUE}, {"mvd13", 13, TRUE}, {"mvd14", 14, TRUE}, {"mvd15", 15, TRUE},
-  {NULL, 0, TRUE}
-};
-
-static const struct reg_entry mav_mvfx_table[] =
-{
-  {"mvfx0",  0, TRUE},  {"mvfx1",  1, TRUE},  {"mvfx2",  2, TRUE},  {"mvfx3",  3, TRUE},
-  {"mvfx4",  4, TRUE},  {"mvfx5",  5, TRUE},  {"mvfx6",  6, TRUE},  {"mvfx7",  7, TRUE},
-  {"mvfx8",  8, TRUE},  {"mvfx9",  9, TRUE},  {"mvfx10", 10, TRUE}, {"mvfx11", 11, TRUE},
-  {"mvfx12", 12, TRUE}, {"mvfx13", 13, TRUE}, {"mvfx14", 14, TRUE}, {"mvfx15", 15, TRUE},
-  {NULL, 0, TRUE}
-};
-
-static const struct reg_entry mav_mvdx_table[] =
-{
-  {"mvdx0",  0, TRUE},  {"mvdx1",  1, TRUE},  {"mvdx2",  2, TRUE},  {"mvdx3",  3, TRUE},
-  {"mvdx4",  4, TRUE},  {"mvdx5",  5, TRUE},  {"mvdx6",  6, TRUE},  {"mvdx7",  7, TRUE},
-  {"mvdx8",  8, TRUE},  {"mvdx9",  9, TRUE},  {"mvdx10", 10, TRUE}, {"mvdx11", 11, TRUE},
-  {"mvdx12", 12, TRUE}, {"mvdx13", 13, TRUE}, {"mvdx14", 14, TRUE}, {"mvdx15", 15, TRUE},
-  {NULL, 0, TRUE}
-};
-
-static const struct reg_entry mav_mvax_table[] =
-{
-  {"mvax0", 0, TRUE}, {"mvax1", 1, TRUE}, {"mvax2", 2, TRUE}, {"mvax3", 3, TRUE},
-  {NULL, 0, TRUE}
-};
-
-static const struct reg_entry mav_dspsc_table[] =
-{
-  {"dspsc", 0, TRUE},
-  {NULL, 0, TRUE}
-};
-
-struct reg_map
-{
-  const struct reg_entry * names;
-  int                      max_regno;
-  struct hash_control *    htab;
-  const char *             expected;
-};
-
-struct reg_map all_reg_maps[] =
-{
-  {rn_table,        15, NULL, N_("ARM register expected")},
-  {cp_table,        15, NULL, N_("bad or missing co-processor number")},
-  {cn_table,        15, NULL, N_("co-processor register expected")},
-  {fn_table,         7, NULL, N_("FPA register expected")},
-  {sn_table,	    31, NULL, N_("VFP single precision register expected")},
-  {dn_table,	    15, NULL, N_("VFP double precision register expected")},
-  {mav_mvf_table,   15, NULL, N_("Maverick MVF register expected")},
-  {mav_mvd_table,   15, NULL, N_("Maverick MVD register expected")},
-  {mav_mvfx_table,  15, NULL, N_("Maverick MVFX register expected")},
-  {mav_mvdx_table,  15, NULL, N_("Maverick MVDX register expected")},
-  {mav_mvax_table,   3, NULL, N_("Maverick MVAX register expected")},
-  {mav_dspsc_table,  0, NULL, N_("Maverick DSPSC register expected")},
-  {iwmmxt_table,    23, NULL, N_("Intel Wireless MMX technology register expected")},
-};
-
-/* Enumeration matching entries in table above.  */
+/* ARM register categories.  This includes coprocessor numbers and various
+   architecture extensions' registers.  */
 enum arm_reg_type
 {
   REG_TYPE_RN = 0,
-#define REG_TYPE_FIRST REG_TYPE_RN
   REG_TYPE_CP = 1,
   REG_TYPE_CN = 2,
   REG_TYPE_FN = 3,
@@ -760,11 +557,47 @@
   REG_TYPE_MVDX = 9,
   REG_TYPE_MVAX = 10,
   REG_TYPE_DSPSC = 11,
-  REG_TYPE_IWMMXT = 12,
+  REG_TYPE_MMXWR = 12,
+  REG_TYPE_MMXWC = 13,
+  REG_TYPE_MMXWCG = 14,
+  REG_TYPE_XSCALE = 15,
+};
 
-  REG_TYPE_MAX = 13
+/* Structure for a hash table entry for a register.  */
+struct reg_entry
+{
+  const char   *name;
+  unsigned char number;
+  unsigned char type;
+  unsigned char builtin;
 };
 
+/* Diagnostics used when we don't get a register of the expected type.  */
+const char *const reg_expected_msgs[] =
+{
+  N_("ARM register expected"),
+  N_("bad or missing co-processor number"),
+  N_("co-processor register expected"),
+  N_("FPA register expected"),
+  N_("VFP single precision register expected"),
+  N_("VFP double precision register expected"),
+  N_("Maverick MVF register expected"),
+  N_("Maverick MVD register expected"),
+  N_("Maverick MVFX register expected"),
+  N_("Maverick MVDX register expected"),
+  N_("Maverick MVAX register expected"),
+  N_("Maverick DSPSC register expected"),
+  N_("iWMMXt data register expected"),
+  N_("iWMMXt control register expected"),
+  N_("iWMMXt scalar register expected"),
+  N_("XScale accumulator register expected"),
+};
+
+/* Some well known registers that we refer to directly elsewhere.  */
+#define REG_SP  13
+#define REG_LR  14
+#define REG_PC	15
+
 /* ARM instructions take 4bytes in the object file, Thumb instructions
    take 2:  */
 #define INSN_SIZE       4
@@ -938,13 +771,13 @@
 #define BAD_ARGS 	_("bad arguments to instruction")
 #define BAD_PC 		_("r15 not allowed here")
 #define BAD_COND 	_("instruction is not conditional")
-#define BAD_ACCUM	_("acc0 expected")
 
-static struct hash_control * arm_ops_hsh   = NULL;
-static struct hash_control * arm_tops_hsh  = NULL;
-static struct hash_control * arm_cond_hsh  = NULL;
-static struct hash_control * arm_shift_hsh = NULL;
-static struct hash_control * arm_psr_hsh   = NULL;
+static struct hash_control *arm_ops_hsh;
+static struct hash_control *arm_tops_hsh;
+static struct hash_control *arm_cond_hsh;
+static struct hash_control *arm_shift_hsh;
+static struct hash_control *arm_psr_hsh;
+static struct hash_control *arm_reg_hsh;
 
 /* Stuff needed to resolve the label ambiguity
    As:
@@ -1440,98 +1273,71 @@
 
 /* Register parsing.  */
 
-/* arm_reg_parse () := if it looks like a register, return its token and
-   advance the pointer.  */
+/* Generic register parser.  CCP points to what should be the
+   beginning of a register name.  If it is indeed a valid register
+   name, of type TYPE, return the associated register number.  If it
+   is not, return FAIL.  Does not issue diagnostics.  */
 
 static int
-arm_reg_parse (char ** ccp, struct hash_control * htab)
+arm_reg_parse (char **ccp, enum arm_reg_type type)
 {
-  char * start = * ccp;
-  char   c;
-  char * p;
-  struct reg_entry * reg;
+  char *start = *ccp;
+  char *p;
+  struct reg_entry *reg;
 
 #ifdef REGISTER_PREFIX
   if (*start != REGISTER_PREFIX)
     return FAIL;
-  p = start + 1;
-#else
-  p = start;
+  start++;
+#endif
 #ifdef OPTIONAL_REGISTER_PREFIX
-  if (*p == OPTIONAL_REGISTER_PREFIX)
-    p++, start++;
+  if (*start == OPTIONAL_REGISTER_PREFIX)
+    start++;
 #endif
-#endif
+
+  p = start;
   if (!ISALPHA (*p) || !is_name_beginner (*p))
     return FAIL;
 
-  c = *p++;
-  while (ISALPHA (c) || ISDIGIT (c) || c == '_')
-    c = *p++;
+  do
+    p++;
+  while (ISALPHA (*p) || ISDIGIT (*p) || *p == '_');
 
-  *--p = 0;
-  reg = (struct reg_entry *) hash_find (htab, start);
-  *p = c;
+  reg = (struct reg_entry *) hash_find_n (arm_reg_hsh, start, p - start);
 
-  if (reg)
-    {
-      *ccp = p;
-      return reg->number;
-    }
-
-  return FAIL;
+  if (!reg || reg->type != type)
+    return FAIL;
+  
+  *ccp = p;
+  return reg->number;
 }
 
-/* Search for the following register name in each of the possible reg name
-   tables.  Return the classification if found, or REG_TYPE_MAX if not
-   present.  */
+/* A standard register must be given at this point.  SHIFT is the
+   place to put it in inst.instruction.  Restores input start point on
+   error.  Returns the reg#, or FAIL.  */
 
-static enum arm_reg_type
-arm_reg_parse_any (char *cp)
-{
-  int i;
-
-  for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++)
-    if (arm_reg_parse (&cp, all_reg_maps[i].htab) != FAIL)
-      return (enum arm_reg_type) i;
-
-  return REG_TYPE_MAX;
-}
-
-/* A standard register must be given at this point.
-   SHIFT is the place to put it in inst.instruction.
-   Restores input start point on error.
-   Returns the reg#, or FAIL.  */
-
 static int
 reg_required_here (char ** str, int shift, bfd_boolean no_pc)
 {
-  static char buff [128]; /* XXX  */
-  int         reg;
-  char *      start = * str;
+  int reg;
+  char *start = *str;
 
-  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_RN].htab)) != FAIL)
+  if ((reg = arm_reg_parse (str, REG_TYPE_RN)) == FAIL)
     {
-      if (reg == REG_PC && no_pc)
-	{
-	  inst.error = BAD_PC;
-	  return FAIL;
-	}
+      inst.error = gettext (reg_expected_msgs[REG_TYPE_RN]);
+      return FAIL;
+    }
 
-      if (shift >= 0)
-	inst.instruction |= reg << shift;
-      return reg;
+  if (reg == REG_PC && no_pc)
+    {
+      inst.error = BAD_PC;
+      *str = start;
+      return FAIL;
     }
 
-  /* Restore the start point, we may have got a reg of the wrong class.  */
-  *str = start;
-
-  /* In the few cases where we might be able to accept something else
-     this error can be overridden.  */
-  sprintf (buff, _("register expected, not '%.100s'"), start);
-  inst.error = buff;
-
-  return FAIL;
+  if (shift >= 0)
+    inst.instruction |= reg << shift;
+  return reg;
 }
 
 #define reg_or_fail(str, shift, no_pc)			\
@@ -1610,105 +1416,93 @@
 }
 
 static int
-vfp_sp_reg_required_here (char ** str,
-			  enum vfp_sp_reg_pos pos)
+vfp_sp_reg_required_here (char **str, enum vfp_sp_reg_pos pos)
 {
-  int    reg;
-  char * start = *str;
+  int reg;
 
-  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_SN].htab)) != FAIL)
+  if ((reg = arm_reg_parse (str, REG_TYPE_SN)) == FAIL)
     {
+      inst.error = gettext (reg_expected_msgs[REG_TYPE_SN]);
+      return FAIL;
+    }
+  else
+    {
       vfp_sp_encode_reg (reg, pos);
       return reg;
     }
-
-  /* In the few cases where we might be able to accept something else
-     this error can be overridden.  */
-  inst.error = _(all_reg_maps[REG_TYPE_SN].expected);
-
-  /* Restore the start point.  */
-  *str = start;
-  return FAIL;
 }
 
-static int
-vfp_dp_reg_required_here (char ** str,
-			  enum vfp_dp_reg_pos pos)
+static void
+vfp_dp_encode_reg (int reg, enum vfp_sp_reg_pos pos)
 {
-  int    reg;
-  char * start = *str;
-
-  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_DN].htab)) != FAIL)
+  switch (pos)
     {
-      switch (pos)
-	{
-	case VFP_REG_Dd:
-	  inst.instruction |= reg << 12;
-	  break;
+    case VFP_REG_Dd:
+      inst.instruction |= reg << 12;
+      break;
 
-	case VFP_REG_Dn:
-	  inst.instruction |= reg << 16;
-	  break;
+    case VFP_REG_Dn:
+      inst.instruction |= reg << 16;
+      break;
 
-	case VFP_REG_Dm:
-	  inst.instruction |= reg << 0;
-	  break;
+    case VFP_REG_Dm:
+      inst.instruction |= reg << 0;
+      break;
 
-	default:
-	  abort ();
-	}
-      return reg;
+    default:
+      abort ();
     }
+}
 
-  /* In the few cases where we might be able to accept something else
-     this error can be overridden.  */
-  inst.error = _(all_reg_maps[REG_TYPE_DN].expected);
+static int
+vfp_dp_reg_required_here (char **str, enum vfp_dp_reg_pos pos)
+{
+  int reg;
 
-  /* Restore the start point.  */
-  *str = start;
-  return FAIL;
+  if ((reg = arm_reg_parse (str, REG_TYPE_DN)) == FAIL)
+    {
+      inst.error = gettext (reg_expected_msgs[REG_TYPE_DN]);
+      return FAIL;
+    }
+  else
+    {
+      vfp_dp_encode_reg (reg, pos);
+      return reg;
+    }
 }
 
 static int
-fp_reg_required_here (char ** str, int where)
+fp_reg_required_here (char **str, int where)
 {
-  int    reg;
-  char * start = * str;
+  int reg;
 
-  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_FN].htab)) != FAIL)
+  if ((reg = arm_reg_parse (str, REG_TYPE_FN)) == FAIL)
     {
+      inst.error = gettext (reg_expected_msgs[REG_TYPE_FN]);
+      return FAIL;
+    }
+  else
+    {
       inst.instruction |= reg << where;
       return reg;
     }
-
-  /* In the few cases where we might be able to accept something else
-     this error can be overridden.  */
-  inst.error = all_reg_maps[REG_TYPE_FN].expected;
-
-  /* Restore the start point.  */
-  *str = start;
-  return FAIL;
 }
 
 static int
-cp_reg_required_here (char ** str, int where)
+cp_reg_required_here (char **str, int where)
 {
-  int    reg;
-  char * start = *str;
+  int reg;
 
-  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL)
+  if ((reg = arm_reg_parse (str, REG_TYPE_CN)) == FAIL)
     {
+      inst.error = gettext (reg_expected_msgs[REG_TYPE_CN]);
+      return FAIL;
+    }
+  else
+    {
       inst.instruction |= reg << where;
       return reg;
     }
-
-  /* In the few cases where we might be able to accept something else
-     this error can be overridden.  */
-  inst.error = all_reg_maps[REG_TYPE_CN].expected;
-
-  /* Restore the start point.  */
-  *str = start;
-  return FAIL;
 }
 
 /* A Intel Wireless MMX technology register
@@ -1718,47 +1512,44 @@
    Returns the reg#, or FAIL.  */
 
 static int
-wreg_required_here (char ** str,
-		    int shift,
-		    enum wreg_type reg_type)
+wreg_required_here (char **str, int shift, enum wreg_type reg_type)
 {
-  static char buff [128];
-  int    reg;
-  char * start = *str;
+  int reg;
 
-  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_IWMMXT].htab)) != FAIL)
+  switch (reg_type)
     {
-      if (wr_register (reg)
-	  && (reg_type == IWMMXT_REG_WR || reg_type == IWMMXT_REG_WR_OR_WC))
-        {
-          if (shift >= 0)
-            inst.instruction |= (reg ^ WR_PREFIX) << shift;
-          return reg;
-        }
-      else if (wc_register (reg)
-	       && (reg_type == IWMMXT_REG_WC || reg_type == IWMMXT_REG_WR_OR_WC))
-        {
-          if (shift >= 0)
-            inst.instruction |= (reg ^ WC_PREFIX) << shift;
-          return reg;
-        }
-      else if ((wcg_register (reg) && reg_type == IWMMXT_REG_WCG))
-        {
-          if (shift >= 0)
-            inst.instruction |= ((reg ^ WC_PREFIX) - 8) << shift;
-          return reg;
-        }
-    }
+    case IWMMXT_REG_WR:
+      if ((reg = arm_reg_parse (str, REG_TYPE_MMXWR)) == FAIL)
+	{
+	  inst.error = gettext (reg_expected_msgs[REG_TYPE_MMXWR]);
+	  return FAIL;
+	}
+      break;
 
-  /* Restore the start point, we may have got a reg of the wrong class.  */
-  *str = start;
+    case IWMMXT_REG_WC:
+      if ((reg = arm_reg_parse (str, REG_TYPE_MMXWC)) == FAIL)
+	{
+	  inst.error = gettext (reg_expected_msgs[REG_TYPE_MMXWC]);
+	  return FAIL;
+	}
+      break;
 
-  /* In the few cases where we might be able to accept
-     something else this error can be overridden.  */
-  sprintf (buff, _("Intel Wireless MMX technology register expected, not '%.100s'"), start);
-  inst.error = buff;
+    case IWMMXT_REG_WCG:
+      if ((reg = arm_reg_parse (str, REG_TYPE_MMXWCG)) == FAIL)
+	{
+	  inst.error = gettext (reg_expected_msgs[REG_TYPE_MMXWCG]);
+	  return FAIL;
+	}
+      break;
 
-  return FAIL;
+    default:
+      abort ();
+    }
+
+  if (shift >= 0)
+    inst.instruction |= reg << shift;
+
+  return reg;
 }
 
 /* A register must be given at this point.
@@ -1774,7 +1565,7 @@
   int   reg;
   char *start = *str;
 
-  if ((reg = arm_reg_parse (str, all_reg_maps[regtype].htab)) != FAIL)
+  if ((reg = arm_reg_parse (str, regtype)) != FAIL)
     {
       if (shift >= 0)
 	inst.instruction |= reg << shift;
@@ -1791,7 +1582,7 @@
       regtype == REG_TYPE_MVFX ||
       regtype == REG_TYPE_MVDX)
     {
-      if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL)
+      if ((reg = arm_reg_parse (str, REG_TYPE_CN)) != FAIL)
 	{
 	  if (shift >= 0)
 	    inst.instruction |= reg << shift;
@@ -1805,7 +1596,7 @@
 
   /* In the few cases where we might be able to accept something else
      this error can be overridden.  */
-  inst.error = _(all_reg_maps[regtype].expected);
+  inst.error = gettext (reg_expected_msgs[regtype]);
 
   return FAIL;
 }
@@ -1822,13 +1613,13 @@
 {
   skip_whitespace (*str);
 
-  if (strncasecmp (*str, "acc0", 4) != 0 || ISALNUM ((*str)[4]))
+  if (arm_reg_parse (str, REG_TYPE_XSCALE) == FAIL)
     {
-      inst.error = BAD_ACCUM;
+      inst.error = gettext (reg_expected_msgs[REG_TYPE_XSCALE]);
       return FAIL;
     }
-  *str += 4;
-  return 0;
+  else
+    return 0;
 }
 
 /* Register lists.  */
@@ -1996,10 +1787,10 @@
 
   do
     {
-      new_base = arm_reg_parse (str, all_reg_maps[regtype].htab);
+      new_base = arm_reg_parse (str, regtype);
       if (new_base == FAIL)
 	{
-	  inst.error = _(all_reg_maps[regtype].expected);
+	  inst.error = gettext (reg_expected_msgs[regtype]);
 	  return FAIL;
 	}
 
@@ -2029,11 +1820,9 @@
 
 	  (*str)++;
 
-	  if ((high_range
-	       = arm_reg_parse (str, all_reg_maps[regtype].htab))
-	      == FAIL)
+	  if ((high_range = arm_reg_parse (str, regtype)) == FAIL)
 	    {
-	      inst.error = _(all_reg_maps[regtype].expected);
+	      inst.error = gettext (reg_expected_msgs[regtype]);
 	      return FAIL;
 	    }
 
@@ -2848,7 +2637,7 @@
 static int
 co_proc_number (char ** str)
 {
-  int processor, pchar;
+  int processor;
   char *start;
 
   skip_whitespace (*str);
@@ -2857,28 +2646,13 @@
   /* The data sheet seems to imply that just a number on its own is valid
      here, but the RISC iX assembler seems to accept a prefix 'p'.  We will
      accept either.  */
-  if ((processor = arm_reg_parse (str, all_reg_maps[REG_TYPE_CP].htab))
-      == FAIL)
+  if ((processor = arm_reg_parse (str, REG_TYPE_CP)) == FAIL)
     {
-      *str = start;
-
-      pchar = *(*str)++;
-      if (pchar >= '0' && pchar <= '9')
+      processor = strtoul (start, str, 10);
+      if (start == *str || processor > 15)
 	{
-	  processor = pchar - '0';
-	  if (**str >= '0' && **str <= '9')
-	    {
-	      processor = processor * 10 + *(*str)++ - '0';
-	      if (processor > 15)
-		{
-		  inst.error = _("illegal co-processor number");
-		  return FAIL;
-		}
-	    }
-	}
-      else
-	{
-	  inst.error = all_reg_maps[REG_TYPE_CP].expected;
+	  *str = start;
+	  inst.error = reg_expected_msgs[REG_TYPE_CP];
 	  return FAIL;
 	}
     }
@@ -3336,28 +3110,34 @@
 /* Directives: register aliases.  */
 
 static void
-insert_reg_alias (char * str,
-		  int regnum,
-		  struct hash_control *htab)
+insert_reg_alias (char *str, int number, int type)
 {
-  const char * error;
-  struct reg_entry * new = xmalloc (sizeof (struct reg_entry));
-  const char * name = xmalloc (strlen (str) + 1);
+  struct reg_entry *new;
+  const char *name;
 
-  strcpy ((char *) name, str);
+  if ((new = hash_find (arm_reg_hsh, str)) != 0)
+    {
+      if (new->builtin)
+	as_warn (_("ignoring attempt to redefine built-in register '%s'"), str);
+      
+      /* Only warn about a redefinition if it's not defined as the
+	 same register.  */
+      else if (new->number != number || new->type != type)
+	as_warn (_("ignoring redefinition of register alias '%s'"), str);
 
+      return;
+    }
+
+  name = xstrdup (str);
+  new = xmalloc (sizeof (struct reg_entry));
+
   new->name = name;
-  new->number = regnum;
+  new->number = number;
+  new->type = type;
   new->builtin = FALSE;
 
-  error = hash_insert (htab, name, (PTR) new);
-  if (error)
-    {
-      as_bad (_("failed to create an alias for %s, reason: %s"),
-	    str, error);
-      free ((char *) name);
-      free (new);
-    }
+  if (hash_insert (arm_reg_hsh, name, (PTR) new))
+    abort ();
 }
 
 /* Look for the .req directive.  This is of the form:
@@ -3368,82 +3148,61 @@
    handle any error here, return non-zero.  Otherwise return zero.  */
 
 static int
-create_register_alias (char * newname, char * p)
+create_register_alias (char * newname, char *p)
 {
-  char * q;
-  char c;
+  struct reg_entry *old;
+  char *oldname, *nbuf;
+  size_t nlen;
 
-  q = p;
-  skip_whitespace (q);
+  /* The input scrubber ensures that whitespace after the mnemonic is
+     collapsed to single spaces.  */
+  oldname = p;
+  if (strncmp (oldname, " .req ", 6) != 0)
+    return 0;
 
-  c = *p;
-  *p = '\0';
+  oldname += 6;
+  if (*oldname == '\0')
+    return 0;
 
-  if (*q && !strncmp (q, ".req ", 5))
+  old = hash_find (arm_reg_hsh, oldname);
+  if (!old)
     {
-      char *copy_of_str;
-      char *r;
+      as_warn (_("unknown register '%s' -- .req ignored"), oldname);
+      return 1;
+    }
 
-#ifndef IGNORE_OPCODE_CASE
-      newname = original_case_string;
+  /* If TC_CASE_SENSITIVE is defined, then newname already points to
+     the desired alias name, and p points to its end.  If not, then
+     the desired alias name is in the global original_case_string.  */
+#ifdef TC_CASE_SENSITIVE
+  nlen = p - newname;
+#else
+  newname = original_case_string;
+  nlen = strlen (newname);
 #endif
-      copy_of_str = newname;
 
-      q += 4;
-      skip_whitespace (q);
+  nbuf = alloca (nlen + 1);
+  memcpy (nbuf, newname, nlen);
+  nbuf[nlen] = '\0';
 
-      for (r = q; *r != '\0'; r++)
-	if (*r == ' ')
-	  break;
+  /* Create aliases under the new name as stated; an all-lowercase
+     version of the new name; and an all-uppercase version of the new
+     name.  */
+  insert_reg_alias (nbuf, old->number, old->type);
 
-      if (r != q)
-	{
-	  enum arm_reg_type new_type, old_type;
-	  int old_regno;
-	  char d = *r;
+  for (p = nbuf; *p; p++)
+    *p = TOUPPER (*p);
 
-	  *r = '\0';
-	  old_type = arm_reg_parse_any (q);
-	  *r = d;
+  if (strncmp (nbuf, newname, nlen))
+    insert_reg_alias (nbuf, old->number, old->type);
 
-	  new_type = arm_reg_parse_any (newname);
+  for (p = nbuf; *p; p++)
+    *p = TOLOWER (*p);
 
-	  if (new_type == REG_TYPE_MAX)
-	    {
-	      if (old_type != REG_TYPE_MAX)
-		{
-		  old_regno = arm_reg_parse (&q, all_reg_maps[old_type].htab);
-		  insert_reg_alias (newname, old_regno,
-				    all_reg_maps[old_type].htab);
-		}
-	      else
-		as_warn (_("register '%s' does not exist\n"), q);
-	    }
-	  else if (old_type == REG_TYPE_MAX)
-	    {
-	      as_warn (_("ignoring redefinition of register alias '%s' to non-existant register '%s'"),
-		       copy_of_str, q);
-	    }
-	  else
-	    {
-	      /* Do not warn about redefinitions to the same alias.  */
-	      if (new_type != old_type
-		  || (arm_reg_parse (&q, all_reg_maps[old_type].htab)
-		      != arm_reg_parse (&q, all_reg_maps[new_type].htab)))
-		as_warn (_("ignoring redefinition of register alias '%s'"),
-			 copy_of_str);
+  if (strncmp (nbuf, newname, nlen))
+    insert_reg_alias (nbuf, old->number, old->type);
 
-	    }
-	}
-      else
-	as_warn (_("ignoring incomplete .req pseuso op"));
-
-      *p = c;
-      return 1;
-    }
-
-  *p = c;
-  return 0;
+  return 1;
 }
 
 /* Should never be called, as .req goes between the alias and the
@@ -3477,49 +3236,24 @@
   saved_char = *input_line_pointer;
   *input_line_pointer = 0;
 
-  if (*name)
+  if (!*name)
+    as_bad (_("invalid syntax for .unreq directive"));
+  else
     {
-      enum arm_reg_type req_type = arm_reg_parse_any (name);
+      struct reg_entry *reg = hash_find (arm_reg_hsh, name);
 
-      if (req_type != REG_TYPE_MAX)
+      if (!reg)
+        as_bad (_("unknown register alias '%s'"), name);
+      else if (reg->builtin)
+	as_warn (_("ignoring attempt to undefine built-in register '%s'"),
+		 name);
+      else
 	{
-	  char *temp_name = name;
-	  int req_no = arm_reg_parse (&temp_name, all_reg_maps[req_type].htab);
-
-	  if (req_no != FAIL)
-	    {
-	      struct reg_entry *req_entry;
-
-	      /* Check to see if this alias is a builtin one.  */
-	      req_entry = hash_delete (all_reg_maps[req_type].htab, name);
-
-	      if (!req_entry)
-		as_bad (_("unreq: missing hash entry for \"%s\""), name);
-	      else if (req_entry->builtin)
-		/* FIXME: We are deleting a built in register alias which
-		   points to a const data structure, so we only need to
-		   free up the memory used by the key in the hash table.
-		   Unfortunately we have not recorded this value, so this
-		   is a memory leak.  */
-		  /* FIXME: Should we issue a warning message ?  */
-		;
-	      else
-		{
-		  /* Deleting a user defined alias.  We need to free the
-		     key and the value, but fortunately the key is the same
-		     as the value->name field.  */
-		  free ((char *) req_entry->name);
-		  free (req_entry);
-		}
-	    }
-          else
-            as_bad (_(".unreq: unrecognized symbol \"%s\""), name);
+	  hash_delete (arm_reg_hsh, name);
+	  free ((char *) reg->name);
+	  free (reg);
 	}
-      else
-        as_bad (_(".unreq: unrecognized symbol \"%s\""), name);
     }
-  else
-    as_bad (_("invalid syntax for .unreq directive"));
 
   *input_line_pointer = saved_char;
   demand_empty_rest_of_line ();
@@ -4576,68 +4310,51 @@
 }
 
 
-/* Parse a directive saving iWMMXt registers.  */
+/* Parse a directive saving iWMMXt data registers.  */
 
 static void
-s_arm_unwind_save_wmmx (void)
+s_arm_unwind_save_mmxwr (void)
 {
   int reg;
   int hi_reg;
   int i;
-  unsigned wcg_mask;
-  unsigned wr_mask;
+  unsigned mask = 0;
   valueT op;
 
   if (*input_line_pointer == '{')
     input_line_pointer++;
 
-  wcg_mask = 0;
-  wr_mask = 0;
   do
     {
-      reg = arm_reg_parse (&input_line_pointer,
-			   all_reg_maps[REG_TYPE_IWMMXT].htab);
+      reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
 
-      if (wr_register (reg))
+      if (reg == FAIL)
 	{
-	  i = reg & ~WR_PREFIX;
-	  if (wr_mask >> i)
-	    as_tsktsk (_("register list not in ascending order"));
-	  wr_mask |= 1 << i;
-	}
-      else if (wcg_register (reg))
-	{
-	  i = (reg & ~WC_PREFIX) - 8;
-	  if (wcg_mask >> i)
-	    as_tsktsk (_("register list not in ascending order"));
-	  wcg_mask |= 1 << i;
-	}
-      else
-	{
-	  as_bad (_("expected wr or wcgr"));
+	  as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR]));
 	  goto error;
 	}
 
+      if (mask >> reg)
+	as_tsktsk (_("register list not in ascending order"));
+      mask |= 1 << reg;
+
       SKIP_WHITESPACE ();
       if (*input_line_pointer == '-')
 	{
-	  hi_reg = arm_reg_parse (&input_line_pointer,
-				  all_reg_maps[REG_TYPE_IWMMXT].htab);
-	  if (wr_register (reg) && wr_register (hi_reg))
+	  input_line_pointer++;
+	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
+	  if (hi_reg == FAIL)
 	    {
-	      for (; reg < hi_reg; reg++)
-		wr_mask |= 1 << (reg & ~WR_PREFIX);
+	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR]));
+	      goto error;
 	    }
-	  else if (wcg_register (reg) && wcg_register (hi_reg))
+	  else if (reg >= hi_reg)
 	    {
-	      for (; reg < hi_reg; reg++)
-		wcg_mask |= 1 << ((reg & ~WC_PREFIX) - 8);
-	    }
-	  else
-	    {
 	      as_bad (_("bad register range"));
 	      goto error;
 	    }
+	  for (; reg < hi_reg; reg++)
+	    mask |= 1 << reg;
 	}
     }
   while (skip_past_comma (&input_line_pointer) != FAIL);
@@ -4648,106 +4365,158 @@
 
   demand_empty_rest_of_line ();
 
-  if (wr_mask && wcg_mask)
-    {
-      as_bad (_("inconsistent register types"));
-      goto error;
-    }
-
   /* Generate any deferred opcodes becuuse we're going to be looking at
      the list.  */
   flush_pending_unwind ();
 
-  if (wcg_mask)
+  for (i = 0; i < 16; i++)
     {
-      for (i = 0; i < 16; i++)
-	{
-	  if (wcg_mask & (1 << i))
-	    unwind.frame_size += 4;
-	}
-      op = 0xc700 | wcg_mask;
-      add_unwind_opcode (op, 2);
+      if (mask & (1 << i))
+	unwind.frame_size += 8;
     }
-  else
+
+  /* Attempt to combine with a previous opcode.  We do this because gcc
+     likes to output separate unwind directives for a single block of
+     registers.  */
+  if (unwind.opcode_count > 0)
     {
-      for (i = 0; i < 16; i++)
+      i = unwind.opcodes[unwind.opcode_count - 1];
+      if ((i & 0xf8) == 0xc0)
 	{
-	  if (wr_mask & (1 << i))
-	    unwind.frame_size += 8;
-	}
-      /* Attempt to combine with a previous opcode.  We do this because gcc
-	 likes to output separate unwind directives for a single block of
-	 registers.  */
-      if (unwind.opcode_count > 0)
-	{
-	  i = unwind.opcodes[unwind.opcode_count - 1];
-	  if ((i & 0xf8) == 0xc0)
+	  i &= 7;
+	  /* Only merge if the blocks are contiguous.  */
+	  if (i < 6)
 	    {
-	      i &= 7;
-	      /* Only merge if the blocks are contiguous.  */
-	      if (i < 6)
+	      if ((mask & 0xfe00) == (1 << 9))
 		{
-		  if ((wr_mask & 0xfe00) == (1 << 9))
-		    {
-		      wr_mask |= ((1 << (i + 11)) - 1) & 0xfc00;
-		      unwind.opcode_count--;
-		    }
+		  mask |= ((1 << (i + 11)) - 1) & 0xfc00;
+		  unwind.opcode_count--;
 		}
-	      else if (i == 6 && unwind.opcode_count >= 2)
-		{
-		  i = unwind.opcodes[unwind.opcode_count - 2];
-		  reg = i >> 4;
-		  i &= 0xf;
+	    }
+	  else if (i == 6 && unwind.opcode_count >= 2)
+	    {
+	      i = unwind.opcodes[unwind.opcode_count - 2];
+	      reg = i >> 4;
+	      i &= 0xf;
 
-		  op = 0xffff << (reg - 1);
-		  if (reg > 0
-		      || ((wr_mask & op) == (1u << (reg - 1))))
-		    {
-		      op = (1 << (reg + i + 1)) - 1;
-		      op &= ~((1 << reg) - 1);
-		      wr_mask |= op;
-		      unwind.opcode_count -= 2;
-		    }
+	      op = 0xffff << (reg - 1);
+	      if (reg > 0
+		  || ((mask & op) == (1u << (reg - 1))))
+		{
+		  op = (1 << (reg + i + 1)) - 1;
+		  op &= ~((1 << reg) - 1);
+		  mask |= op;
+		  unwind.opcode_count -= 2;
 		}
 	    }
 	}
+    }
 
-      hi_reg = 15;
-      /* We want to generate opcodes in the order the registers have been
-	 saved, ie. descending order.  */
-      for (reg = 15; reg >= -1; reg--)
+  hi_reg = 15;
+  /* We want to generate opcodes in the order the registers have been
+     saved, ie. descending order.  */
+  for (reg = 15; reg >= -1; reg--)
+    {
+      /* Save registers in blocks.  */
+      if (reg < 0
+	  || !(mask & (1 << reg)))
 	{
-	  /* Save registers in blocks.  */
-	  if (reg < 0
-	      || !(wr_mask & (1 << reg)))
+	  /* We found an unsaved reg.  Generate opcodes to save the
+	     preceeding block.  */
+	  if (reg != hi_reg)
 	    {
-	      /* We found an unsaved reg.  Generate opcodes to save the
-		 preceeding block.  */
-	      if (reg != hi_reg)
+	      if (reg == 9)
 		{
-		  if (reg == 9)
-		    {
-		      /* Short form.  */
-		      op = 0xc0 | (hi_reg - 10);
-		      add_unwind_opcode (op, 1);
-		    }
-		  else
-		    {
-		      /* Long form.  */
-		      op = 0xc600 | ((reg + 1) << 4) | ((hi_reg - reg) - 1);
-		      add_unwind_opcode (op, 2);
-		    }
+		  /* Short form.  */
+		  op = 0xc0 | (hi_reg - 10);
+		  add_unwind_opcode (op, 1);
 		}
-	      hi_reg = reg - 1;
+	      else
+		{
+		  /* Long form.  */
+		  op = 0xc600 | ((reg + 1) << 4) | ((hi_reg - reg) - 1);
+		  add_unwind_opcode (op, 2);
+		}
 	    }
+	  hi_reg = reg - 1;
 	}
     }
+
   return;
 error:
   ignore_rest_of_line ();
 }
 
+static void
+s_arm_unwind_save_mmxwcg (void)
+{
+  int reg;
+  int hi_reg;
+  unsigned mask = 0;
+  valueT op;
 
+  if (*input_line_pointer == '{')
+    input_line_pointer++;
+
+  do
+    {
+      reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
+
+      if (reg == FAIL)
+	{
+	  as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG]));
+	  goto error;
+	}
+
+      reg -= 8;
+      if (mask >> reg)
+	as_tsktsk (_("register list not in ascending order"));
+      mask |= 1 << reg;
+
+      SKIP_WHITESPACE ();
+      if (*input_line_pointer == '-')
+	{
+	  input_line_pointer++;
+	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
+	  if (hi_reg == FAIL)
+	    {
+	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG]));
+	      goto error;
+	    }
+	  else if (reg >= hi_reg)
+	    {
+	      as_bad (_("bad register range"));
+	      goto error;
+	    }
+	  for (; reg < hi_reg; reg++)
+	    mask |= 1 << reg;
+	}
+    }
+  while (skip_past_comma (&input_line_pointer) != FAIL);
+
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer == '}')
+    input_line_pointer++;
+
+  demand_empty_rest_of_line ();
+
+  /* Generate any deferred opcodes becuuse we're going to be looking at
+     the list.  */
+  flush_pending_unwind ();
+
+  for (reg = 0; reg < 16; reg++)
+    {
+      if (mask & (1 << reg))
+	unwind.frame_size += 4;
+    }
+  op = 0xc700 | mask;
+  add_unwind_opcode (op, 2);
+  return;
+error:
+  ignore_rest_of_line ();
+}
+
+
 /* Parse an unwind_save directive.  */
 
 static void
@@ -4760,7 +4529,7 @@
   SKIP_WHITESPACE ();
   saved_ptr = input_line_pointer;
 
-  reg = arm_reg_parse (&input_line_pointer, all_reg_maps[REG_TYPE_FN].htab);
+  reg = arm_reg_parse (&input_line_pointer, REG_TYPE_FN);
   if (reg != FAIL)
     {
       s_arm_unwind_save_fpa (reg);
@@ -4772,7 +4541,7 @@
 
   SKIP_WHITESPACE ();
 
-  reg = arm_reg_parse (&input_line_pointer, all_reg_maps[REG_TYPE_RN].htab);
+  reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
   if (reg != FAIL)
     {
       input_line_pointer = saved_ptr;
@@ -4780,7 +4549,7 @@
       return;
     }
 
-  reg = arm_reg_parse (&input_line_pointer, all_reg_maps[REG_TYPE_DN].htab);
+  reg = arm_reg_parse (&input_line_pointer, REG_TYPE_DN);
   if (reg != FAIL)
     {
       input_line_pointer = saved_ptr;
@@ -4788,15 +4557,22 @@
       return;
     }
 
-  reg = arm_reg_parse (&input_line_pointer,
-		       all_reg_maps[REG_TYPE_IWMMXT].htab);
+  reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
   if (reg != FAIL)
     {
       input_line_pointer = saved_ptr;
-      s_arm_unwind_save_wmmx ();
+      s_arm_unwind_save_mmxwr ();
       return;
     }
 
+  reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
+  if (reg != FAIL)
+    {
+      input_line_pointer = saved_ptr;
+      s_arm_unwind_save_mmxwcg ();
+      return;
+    }
+
   /* TODO: Maverick registers.  */
   as_bad (_("unrecognised register"));
 }
@@ -9118,7 +8894,7 @@
 
   skip_whitespace (str);
 
-  if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL
+  if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR)) == FAIL
       || skip_past_comma (& str) == FAIL
       || cp_byte_address_required_here (&str) == FAIL)
     {
@@ -9127,13 +8903,6 @@
     }
   else
     end_of_line (str);
-
-  if (wc_register (reg))
-    {
-      as_bad (_("non-word size not supported with control register"));
-      inst.instruction |=  0xf0000100;
-      inst.instruction &= ~0x00400000;
-    }
 }
 
 static void
@@ -9259,25 +9028,30 @@
 
   skip_whitespace (str);
 
-  if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL
-      || skip_past_comma (& str) == FAIL
-      || cp_address_required_here (& str, CP_WB_OK) == FAIL)
+  if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR)) == FAIL)
     {
-      if (! inst.error)
-        inst.error = BAD_ARGS;
-    }
-  else
-    end_of_line (str);
-
-  if (wc_register (reg))
-    {
+      inst.error = 0;
+      if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WC)) == FAIL)
+	return;
+      
       if ((inst.instruction & COND_MASK) != COND_ALWAYS)
-	as_bad (_("conditional execution not supported with control register"));
+	inst.error = _("conditional execution not supported "
+		       "with control register");
       if (op != 2)
-	as_bad (_("non-word size not supported with control register"));
+	inst.error = _("non-word size not supported with control register");
       inst.instruction |=  0xf0000100;
       inst.instruction &= ~0x00400000;
     }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_address_required_here (& str, CP_WB_OK) == FAIL)
+    {
+      if (! inst.error)
+        inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
 }
 
 static void
@@ -10156,8 +9930,107 @@
   return name;
 }
 
-
 
+/* Table of all register names defined by default.  The user can
+   define additional names with .req.  Note that all register names
+   should appear in both upper and lowercase variants.  Some registers
+   also have mixed-case names.  */
+
+#define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, TRUE }
+#define REGNUM(p,n,t) REGDEF(p##n, n, t)
+#define REGSET(p,t) \
+  REGNUM(p, 0,t), REGNUM(p, 1,t), REGNUM(p, 2,t), REGNUM(p, 3,t), \
+  REGNUM(p, 4,t), REGNUM(p, 5,t), REGNUM(p, 6,t), REGNUM(p, 7,t), \
+  REGNUM(p, 8,t), REGNUM(p, 9,t), REGNUM(p,10,t), REGNUM(p,11,t), \
+  REGNUM(p,12,t), REGNUM(p,13,t), REGNUM(p,14,t), REGNUM(p,15,t)
+
+static const struct reg_entry reg_names[] =
+{
+  /* ARM integer registers.  */
+  REGSET(r, RN), REGSET(R, RN),
+
+  /* ATPCS synonyms.  */
+  REGDEF(a1,0,RN), REGDEF(a2,1,RN), REGDEF(a3, 2,RN), REGDEF(a4, 3,RN),
+  REGDEF(v1,4,RN), REGDEF(v2,5,RN), REGDEF(v3, 6,RN), REGDEF(v4, 7,RN),
+  REGDEF(v5,8,RN), REGDEF(v6,9,RN), REGDEF(v7,10,RN), REGDEF(v8,11,RN),
+
+  REGDEF(A1,0,RN), REGDEF(A2,1,RN), REGDEF(A3, 2,RN), REGDEF(A4, 3,RN),
+  REGDEF(V1,4,RN), REGDEF(V2,5,RN), REGDEF(V3, 6,RN), REGDEF(V4, 7,RN),
+  REGDEF(V5,8,RN), REGDEF(V6,9,RN), REGDEF(V7,10,RN), REGDEF(V8,11,RN),
+
+  /* Well-known aliases.  */
+  REGDEF(wr, 7,RN), REGDEF(sb, 9,RN), REGDEF(sl,10,RN), REGDEF(fp,11,RN),
+  REGDEF(ip,12,RN), REGDEF(sp,13,RN), REGDEF(lr,14,RN), REGDEF(pc,15,RN),
+
+  REGDEF(WR, 7,RN), REGDEF(SB, 9,RN), REGDEF(SL,10,RN), REGDEF(FP,11,RN),
+  REGDEF(IP,12,RN), REGDEF(SP,13,RN), REGDEF(LR,14,RN), REGDEF(PC,15,RN),
+
+  /* Coprocessor numbers.  */
+  REGSET(p, CP), REGSET(P, CP),
+
+  /* Coprocessor register numbers.  The "cr" variants are for backward
+     compatibility.  */
+  REGSET(c,  CN), REGSET(C, CN),
+  REGSET(cr, CN), REGSET(CR, CN),
+
+  /* FPA registers.  */
+  REGNUM(f,0,FN), REGNUM(f,1,FN), REGNUM(f,2,FN), REGNUM(f,3,FN),
+  REGNUM(f,4,FN), REGNUM(f,5,FN), REGNUM(f,6,FN), REGNUM(f,7, FN),
+
+  REGNUM(F,0,FN), REGNUM(F,1,FN), REGNUM(F,2,FN), REGNUM(F,3,FN),
+  REGNUM(F,4,FN), REGNUM(F,5,FN), REGNUM(F,6,FN), REGNUM(F,7, FN),
+
+  /* VFP SP registers.  */
+  REGSET(s,SN),
+  REGNUM(s,16,SN), REGNUM(s,17,SN), REGNUM(s,18,SN), REGNUM(s,19,SN),
+  REGNUM(s,20,SN), REGNUM(s,21,SN), REGNUM(s,22,SN), REGNUM(s,23,SN),
+  REGNUM(s,24,SN), REGNUM(s,25,SN), REGNUM(s,26,SN), REGNUM(s,27,SN),
+  REGNUM(s,28,SN), REGNUM(s,29,SN), REGNUM(s,30,SN), REGNUM(s,31,SN),
+
+  REGSET(S,SN),
+  REGNUM(S,16,SN), REGNUM(S,17,SN), REGNUM(S,18,SN), REGNUM(S,19,SN),
+  REGNUM(S,20,SN), REGNUM(S,21,SN), REGNUM(S,22,SN), REGNUM(S,23,SN),
+  REGNUM(S,24,SN), REGNUM(S,25,SN), REGNUM(S,26,SN), REGNUM(S,27,SN),
+  REGNUM(S,28,SN), REGNUM(S,29,SN), REGNUM(S,30,SN), REGNUM(S,31,SN),
+
+  /* VFP DP Registers.  */
+  REGSET(d,DN), REGSET(D,DN),
+
+  
+  /* Maverick DSP coprocessor registers.  */
+  REGSET(mvf,MVF),  REGSET(mvd,MVD),  REGSET(mvfx,MVFX),  REGSET(mvdx,MVDX),
+  REGSET(MVF,MVF),  REGSET(MVD,MVD),  REGSET(MVFX,MVFX),  REGSET(MVDX,MVDX),
+  
+  REGNUM(mvax,0,MVAX), REGNUM(mvax,1,MVAX),
+  REGNUM(mvax,2,MVAX), REGNUM(mvax,3,MVAX),
+  REGDEF(dspsc,0,DSPSC),
+
+  REGNUM(MVAX,0,MVAX), REGNUM(MVAX,1,MVAX),
+  REGNUM(MVAX,2,MVAX), REGNUM(MVAX,3,MVAX),
+  REGDEF(DSPSC,0,DSPSC),
+
+  /* iWMMXt data registers - p0, c0-15.  */
+  REGSET(wr,MMXWR), REGSET(wR,MMXWR), REGSET(WR, MMXWR),
+
+  /* iWMMXt control registers - p1, c0-3.  */
+  REGDEF(wcid,  0,MMXWC),  REGDEF(wCID,  0,MMXWC),  REGDEF(WCID,  0,MMXWC),
+  REGDEF(wcon,  1,MMXWC),  REGDEF(wCon,  1,MMXWC),  REGDEF(WCON,  1,MMXWC),
+  REGDEF(wcssf, 2,MMXWC),  REGDEF(wCSSF, 2,MMXWC),  REGDEF(WCSSF, 2,MMXWC),
+  REGDEF(wcasf, 3,MMXWC),  REGDEF(wCASF, 3,MMXWC),  REGDEF(WCASF, 3,MMXWC),
+
+  /* iWMMXt scalar (constant/offset) registers - p1, c8-11.  */
+  REGDEF(wcgr0, 8,MMXWCG),  REGDEF(wCGR0, 8,MMXWCG),  REGDEF(WCGR0, 8,MMXWCG),
+  REGDEF(wcgr1, 9,MMXWCG),  REGDEF(wCGR1, 9,MMXWCG),  REGDEF(WCGR1, 9,MMXWCG),
+  REGDEF(wcgr2,10,MMXWCG),  REGDEF(wCGR2,10,MMXWCG),  REGDEF(WCGR2,10,MMXWCG),
+  REGDEF(wcgr3,11,MMXWCG),  REGDEF(wCGR3,11,MMXWCG),  REGDEF(WCGR3,11,MMXWCG),
+
+  /* XScale accumulator registers.  */
+  REGNUM(acc,0,XSCALE), REGNUM(ACC,0,XSCALE),
+};
+#undef REGDEF
+#undef REGNUM
+#undef REGSET
+
 static const struct asm_opcode insns[] =
 {
   /* Core ARM Instructions.  */
@@ -11954,13 +11827,12 @@
 int
 tc_arm_regname_to_dw2regnum (const char *regname)
 {
-  unsigned int i;
+  int reg = arm_reg_parse ((char **) &regname, REG_TYPE_RN);
 
-  for (i = 0; rn_table[i].name; i++)
-    if (streq (regname, rn_table[i].name))
-      return rn_table[i].number;
+  if (reg == FAIL)
+    return -1;
 
-  return -1;
+  return reg;
 }
 
 /* Initialize the DWARF-2 unwind information for this procedure.  */
@@ -13160,42 +13032,6 @@
 /* MD interface: Initialization.  */
 
 static void
-insert_reg (const struct reg_entry * r,
-	    struct hash_control * htab)
-{
-  int    len  = strlen (r->name) + 2;
-  char * buf  = xmalloc (len);
-  char * buf2 = xmalloc (len);
-  int    i    = 0;
-
-#ifdef REGISTER_PREFIX
-  buf[i++] = REGISTER_PREFIX;
-#endif
-
-  strcpy (buf + i, r->name);
-
-  for (i = 0; buf[i]; i++)
-    buf2[i] = TOUPPER (buf[i]);
-
-  buf2[i] = '\0';
-
-  hash_insert (htab, buf,  (PTR) r);
-  hash_insert (htab, buf2, (PTR) r);
-}
-
-static void
-build_reg_hsh (struct reg_map * map)
-{
-  const struct reg_entry *r;
-
-  if ((map->htab = hash_new ()) == NULL)
-    as_fatal (_("virtual memory exhausted"));
-
-  for (r = map->names; r->name != NULL; r++)
-    insert_reg (r, map->htab);
-}
-
-static void
 set_constant_flonums (void)
 {
   int i;
@@ -13264,7 +13100,8 @@
       || (arm_tops_hsh = hash_new ()) == NULL
       || (arm_cond_hsh = hash_new ()) == NULL
       || (arm_shift_hsh = hash_new ()) == NULL
-      || (arm_psr_hsh = hash_new ()) == NULL)
+      || (arm_psr_hsh = hash_new ()) == NULL
+      || (arm_reg_hsh = hash_new ()) == NULL)
     as_fatal (_("virtual memory exhausted"));
 
   build_arm_ops_hsh ();
@@ -13276,10 +13113,9 @@
     hash_insert (arm_shift_hsh, shift_names[i].name, (PTR) (shift_names + i));
   for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++)
     hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i));
+  for (i = 0; i < sizeof (reg_names) / sizeof (struct reg_entry); i++)
+    hash_insert (arm_reg_hsh, reg_names[i].name, (PTR) (reg_names + i));
 
-  for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++)
-    build_reg_hsh (all_reg_maps + i);
-
   set_constant_flonums ();
 
   /* Set the cpu variant based on the command-line options.  We prefer

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]