diff --git a/gas/ChangeLog b/gas/ChangeLog index a7569245cc3..d730b2a934a 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,12 @@ +2016-04-07 Andrew Burgess + + * config/tc-arc.c (struct arc_opcode_hash_entry): New structure. + (arc_find_opcode): New function. + (find_special_case_pseudo): Use arc_find_opcode. + (find_special_case_flag): Likewise. + (assemble_tokens): Likewise. + (md_begin): Build hash using struct arc_opcode_hash_entry. + 2016-04-07 Claudiu Zissulescu * config/tc-arc.c (arc_option): Prepare string for automatic diff --git a/gas/config/tc-arc.c b/gas/config/tc-arc.c index ea3464595a9..71c8f253b27 100644 --- a/gas/config/tc-arc.c +++ b/gas/config/tc-arc.c @@ -308,6 +308,16 @@ static struct arc_last_insn bfd_boolean has_delay_slot; } arc_last_insns[2]; +/* Structure to hold an entry in ARC_OPCODE_HASH. */ +struct arc_opcode_hash_entry +{ + /* The number of pointers in the OPCODE list. */ + size_t count; + + /* Points to a list of opcode pointers. */ + const struct arc_opcode **opcode; +}; + /* Forward declaration. */ static void assemble_insn (const struct arc_opcode *, const expressionS *, int, @@ -554,6 +564,29 @@ static bfd_boolean assembling_insn = FALSE; /* Functions implementation. */ +/* Return a pointer to the first entry in ARC_OPCODE_HASH that matches + NAME, or NULL if there are no matching entries. */ + +static const struct arc_opcode * +arc_find_opcode (const char *name) +{ + const struct arc_opcode_hash_entry *entry; + const struct arc_opcode *opcode; + + entry = hash_find (arc_opcode_hash, name); + if (entry != NULL) + { + if (entry->count > 1) + as_fatal (_("unable to lookup `%s', too many opcode chains"), + name); + opcode = *entry->opcode; + } + else + opcode = NULL; + + return opcode; +} + /* Like md_number_to_chars but used for limms. The 4-byte limm value, is encoded as 'middle-endian' for a little-endian target. FIXME! this function is used for regular 4 byte instructions as well. */ @@ -1932,8 +1965,7 @@ find_special_case_pseudo (const char *opname, break; } - return (const struct arc_opcode *) - hash_find (arc_opcode_hash, pseudo_insn->mnemonic_r); + return arc_find_opcode (pseudo_insn->mnemonic_r); } static const struct arc_opcode * @@ -1969,9 +2001,7 @@ find_special_case_flag (const char *opname, flaglen = strlen (flagnm); if (strcmp (opname + oplen, flagnm) == 0) { - opcode = (const struct arc_opcode *) - hash_find (arc_opcode_hash, - arc_flag_special_opcode->name); + opcode = arc_find_opcode (arc_flag_special_opcode->name); if (*nflgs + 1 > MAX_INSN_FLGS) break; @@ -2019,7 +2049,7 @@ assemble_tokens (const char *opname, int cpumatch = 1; /* Search opcodes. */ - opcode = (const struct arc_opcode *) hash_find (arc_opcode_hash, opname); + opcode = arc_find_opcode (opname); /* Couldn't find opcode conventional way, try special cases. */ if (!opcode) @@ -2164,12 +2194,28 @@ md_begin (void) for (i = 0; i < arc_num_opcodes;) { const char *name, *retval; + struct arc_opcode_hash_entry *entry; name = arc_opcodes[i].name; - retval = hash_insert (arc_opcode_hash, name, (void *) &arc_opcodes[i]); - if (retval) - as_fatal (_("internal error: can't hash opcode '%s': %s"), - name, retval); + + entry = hash_find (arc_opcode_hash, name); + if (entry == NULL) + { + entry = xmalloc (sizeof (*entry)); + entry->count = 0; + entry->opcode = NULL; + + retval = hash_insert (arc_opcode_hash, name, (void *) entry); + if (retval) + as_fatal (_("internal error: can't hash opcode '%s': %s"), + name, retval); + } + + entry->opcode = xrealloc (entry->opcode, + sizeof (const struct arc_opcode *) + * entry->count + 1); + entry->opcode [entry->count] = &arc_opcodes[i]; + entry->count++; while (++i < arc_num_opcodes && (arc_opcodes[i].name == name