* cgen.h (*): Clean up pass over `struct foo' usage.

(CGEN_ATTR): Make unsigned char.
	(CGEN_ATTR_TYPE): Update.
	(CGEN_ATTR_{ENTRY,TABLE}): New types.
	(cgen_base): Move member `attrs' to cgen_insn.
	(CGEN_KEYWORD): New member `null_entry'.
	(CGEN_{SYNTAX,FORMAT}): New types.
	(cgen_insn): Format and syntax separated from each other.
This commit is contained in:
Doug Evans 1998-01-12 20:58:56 +00:00
parent e21fb2aec6
commit 19d45995ed
2 changed files with 252 additions and 167 deletions

View File

@ -1,3 +1,14 @@
Mon Jan 12 11:37:36 1998 Doug Evans <devans@seba.cygnus.com>
* cgen.h (*): Clean up pass over `struct foo' usage.
(CGEN_ATTR): Make unsigned char.
(CGEN_ATTR_TYPE): Update.
(CGEN_ATTR_{ENTRY,TABLE}): New types.
(cgen_base): Move member `attrs' to cgen_insn.
(CGEN_KEYWORD): New member `null_entry'.
(CGEN_{SYNTAX,FORMAT}): New types.
(cgen_insn): Format and syntax separated from each other.
start-sanitize-sky
Mon Jan 5 13:33:21 1998 Doug Evans <devans@seba.cygnus.com>

View File

@ -1,6 +1,6 @@
/* Header file for targets using CGEN: Cpu tools GENerator.
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
This file is part of GDB, the GNU debugger, and the GNU Binutils.
@ -14,9 +14,9 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef CGEN_H
#define CGEN_H
@ -82,7 +82,7 @@ enum cgen_endian {
/* Struct to record attribute information. */
typedef struct {
unsigned int num_nonbools;
unsigned char num_nonbools;
unsigned int bool;
unsigned int nonbool[1];
} CGEN_ATTR;
@ -94,7 +94,7 @@ typedef struct {
nonbool: values of non-boolean attributes
There is a maximum of 32 attributes total. */
#define CGEN_ATTR_TYPE(n) \
const struct { unsigned int num_nonbools; \
const struct { unsigned char num_nonbools; \
unsigned int bool; \
unsigned int nonbool[(n) ? (n) : 1]; }
@ -108,6 +108,22 @@ const struct { unsigned int num_nonbools; \
((unsigned int) (attr) < (attr_table)->num_nonbools \
? ((attr_table)->nonbool[attr]) \
: (((attr_table)->bool & (1 << (attr))) != 0))
/* Attribute name/value tables.
These are used to assist parsing of descriptions at runtime. */
typedef struct {
const char *name;
int value;
} CGEN_ATTR_ENTRY;
/* For each domain (fld,operand,insn), list of attributes. */
typedef struct {
const char *name;
/* NULL for boolean attributes. */
const CGEN_ATTR_ENTRY *vals;
} CGEN_ATTR_TABLE;
/* Parse result (also extraction result).
@ -207,11 +223,12 @@ extern cgen_print_fn * CGEN_SYM (print_handlers) [];
#define CGEN_PRINT_FN(x) (CGEN_SYM (print_handlers)[(x)->base.print])
/* Base class of parser/printer.
(Don't read too much into the use of the phrase "base class").
(Don't read too much into the use of the phrase "base class".
It's a name I'm using to organize my thoughts.)
Instructions and expressions all share this data in common.
It's a collection of the common elements needed to parse and print
each of them. */
It's a collection of the common elements needed to parse, insert, extract,
and print each of them. */
#ifndef CGEN_MAX_INSN_ATTRS
#define CGEN_MAX_INSN_ATTRS 1
@ -223,71 +240,81 @@ struct cgen_base {
90% of them would be identical and that's a lot of redundant data.
0 means use the default (what the default is is up to the code). */
unsigned char parse, insert, extract, print;
/* Attributes. */
CGEN_ATTR_TYPE (CGEN_MAX_INSN_ATTRS) attrs;
};
/* Syntax table.
/* Assembler interface.
Each insn and subexpression has one of these.
The interface to the assembler is intended to be clean in the sense that
libopcodes.a is a standalone entity and could be used with any assembler.
Not that one would necessarily want to do that but rather that it helps
keep a clean interface. The interface will obviously be slanted towards
GAS, but at least it's a start.
The syntax "string" consists of characters (n > 0 && n < 128), and operand
values (n >= 128), and is terminated by 0. Operand values are 128 + index
into the operand table. The operand table doesn't exist in C, per se, as
the data is recorded in the parse/insert/extract/print switch statements.
Parsing is controlled by the assembler which calls
CGEN_SYM (assemble_insn). If it can parse and build the entire insn
it doesn't call back to the assembler. If it needs/wants to call back
to the assembler, (*cgen_parse_operand_fn) is called which can either
??? Whether we want to use yacc instead is unclear, but we do make an
effort to not make doing that difficult. At least that's the intent.
*/
- return a number to be inserted in the insn
- return a "register" value to be inserted
(the register might not be a register per pe)
- queue the argument and return a marker saying the expression has been
queued (eg: a fix-up)
- return an error message indicating the expression wasn't recognizable
struct cgen_syntax {
/* Original syntax string, for debugging purposes. */
char *orig;
The result is an error message or NULL for success.
The parsed value is stored in the bfd_vma *. */
/* Name of entry (that distinguishes it from all other entries).
This is used, for example, in simulator profiling results. */
char *name;
#if 0 /* not needed yet */
/* Format of this insn.
This doesn't closely follow the notion of instruction formats for more
complex instruction sets. This is the value computed at runtime. */
enum cgen_fmt_type fmt;
#endif
/* Mnemonic (or name if expression). */
char *mnemonic;
/* Syntax string. */
/* FIXME: If each insn's mnemonic is constant, do we want to record just
the arguments here? */
#ifndef CGEN_MAX_SYNTAX_BYTES
#define CGEN_MAX_SYNTAX_BYTES 16
#endif
unsigned char syntax[CGEN_MAX_SYNTAX_BYTES];
#define CGEN_SYNTAX_CHAR_P(c) ((c) < 128)
#define CGEN_SYNTAX_CHAR(c) (c)
#define CGEN_SYNTAX_FIELD(c) ((c) - 128)
/* recognize insn if (op & mask) == value
For architectures with variable length insns, this is just a preliminary
test. */
/* FIXME: Might want a selectable type (rather than always
unsigned long). */
unsigned long mask, value;
/* length, in bits
This is the size that `mask' and `value' have been calculated to.
Normally it is CGEN_BASE_INSN_BITSIZE. On vliw architectures where
the base insn size may be larger than the size of an insn, this field is
less than CGEN_BASE_INSN_BITSIZE.
On architectures like the 386 and m68k the real size of the insn may
be computed while parsing. */
/* FIXME: wip, of course */
int length;
/* Values for indicating what the caller wants. */
enum cgen_parse_operand_type {
CGEN_PARSE_OPERAND_INIT, CGEN_PARSE_OPERAND_INTEGER,
CGEN_PARSE_OPERAND_ADDRESS
};
/* Values for indicating what was parsed.
??? Not too useful at present but in time. */
enum cgen_parse_operand_result {
CGEN_PARSE_OPERAND_RESULT_NUMBER, CGEN_PARSE_OPERAND_RESULT_REGISTER,
CGEN_PARSE_OPERAND_RESULT_QUEUED, CGEN_PARSE_OPERAND_RESULT_ERROR
};
/* Don't require bfd.h unnecessarily. */
#ifdef BFD_VERSION
extern const char * (*cgen_parse_operand_fn)
PARAMS ((enum cgen_parse_operand_type, const char **, int, int,
enum cgen_parse_operand_result *, bfd_vma *));
#endif
/* Called before trying to match a table entry with the insn. */
void cgen_init_parse_operand PARAMS ((void));
/* Called from <cpu>-asm.c to initialize operand parsing. */
/* These are GAS specific. They're not here as part of the interface,
but rather that we need to put them somewhere. */
/* Call this from md_assemble to initialize the assembler callback. */
void cgen_asm_init_parse PARAMS ((void));
/* Don't require bfd.h unnecessarily. */
#ifdef BFD_VERSION
/* The result is an error message or NULL for success.
The parsed value is stored in the bfd_vma *. */
const char *cgen_parse_operand PARAMS ((enum cgen_parse_operand_type,
const char **, int, int,
enum cgen_parse_operand_result *,
bfd_vma *));
#endif
/* Add a register to the assembler's hash table.
This makes lets GAS parse registers for us.
??? This isn't currently used, but it could be in the future. */
void cgen_asm_record_register PARAMS ((char *, int));
/* After CGEN_SYM (assemble_insn) is done, this is called to
output the insn and record any fixups. */
void cgen_asm_finish_insn PARAMS ((const struct cgen_insn *, cgen_insn_t *,
unsigned int));
/* Operand values (keywords, integers, symbols, etc.) */
@ -325,7 +352,13 @@ typedef struct cgen_keyword_entry {
IDEA: Have "FUNCTION" attribute? [function is called to fetch value]. */
int value;
/* Attributes. */
/* Attributes.
This should, but technically needn't, appear last. It is a variable sized
array in that one architecture may have 1 nonbool attribute and another
may have more. Having this last means the non-architecture specific code
needn't care. */
/* ??? Moving this last should be done by treating keywords like insn lists
and moving the `next' fields into a CGEN_KEYWORD_LIST struct. */
/* FIXME: Not used yet. */
CGEN_ATTR_TYPE (CGEN_MAX_KEYWORD_ATTRS) attrs;
@ -340,61 +373,63 @@ typedef struct cgen_keyword_entry {
This struct supports runtime entry of new values, and hashed lookups. */
typedef struct cgen_keyword {
typedef struct {
/* Pointer to initial [compiled in] values. */
struct cgen_keyword_entry *init_entries;
CGEN_KEYWORD_ENTRY *init_entries;
/* Number of entries in `init_entries'. */
unsigned int num_init_entries;
/* Hash table used for name lookup. */
struct cgen_keyword_entry **name_hash_table;
CGEN_KEYWORD_ENTRY **name_hash_table;
/* Hash table used for value lookup. */
struct cgen_keyword_entry **value_hash_table;
CGEN_KEYWORD_ENTRY **value_hash_table;
/* Number of entries in the hash_tables. */
unsigned int hash_table_size;
/* Pointer to null keyword "" entry if present. */
const CGEN_KEYWORD_ENTRY *null_entry;
} CGEN_KEYWORD;
/* Structure used for searching. */
typedef struct cgen_keyword_search {
typedef struct {
/* Table being searched. */
const struct cgen_keyword *table;
const CGEN_KEYWORD *table;
/* Specification of what is being searched for. */
const char *spec;
/* Current index in hash table. */
unsigned int current_hash;
/* Current element in current hash chain. */
struct cgen_keyword_entry *current_entry;
CGEN_KEYWORD_ENTRY *current_entry;
} CGEN_KEYWORD_SEARCH;
/* Lookup a keyword from its name. */
const struct cgen_keyword_entry * cgen_keyword_lookup_name
PARAMS ((struct cgen_keyword *, const char *));
const CGEN_KEYWORD_ENTRY * cgen_keyword_lookup_name
PARAMS ((CGEN_KEYWORD *, const char *));
/* Lookup a keyword from its value. */
const struct cgen_keyword_entry * cgen_keyword_lookup_value
PARAMS ((struct cgen_keyword *, int));
const CGEN_KEYWORD_ENTRY * cgen_keyword_lookup_value
PARAMS ((CGEN_KEYWORD *, int));
/* Add a keyword. */
void cgen_keyword_add PARAMS ((struct cgen_keyword *,
struct cgen_keyword_entry *));
void cgen_keyword_add PARAMS ((CGEN_KEYWORD *, CGEN_KEYWORD_ENTRY *));
/* Keyword searching.
This can be used to retrieve every keyword, or a subset. */
struct cgen_keyword_search cgen_keyword_search_init
PARAMS ((struct cgen_keyword *, const char *));
const struct cgen_keyword_entry *cgen_keyword_search_next
PARAMS ((struct cgen_keyword_search *));
CGEN_KEYWORD_SEARCH cgen_keyword_search_init
PARAMS ((CGEN_KEYWORD *, const char *));
const CGEN_KEYWORD_ENTRY *cgen_keyword_search_next
PARAMS ((CGEN_KEYWORD_SEARCH *));
/* Operand value support routines. */
/* FIXME: some of the long's here will need to be bfd_vma or some such. */
const char * cgen_parse_keyword PARAMS ((const char **,
struct cgen_keyword *,
CGEN_KEYWORD *,
long *));
const char * cgen_parse_signed_integer PARAMS ((const char **, int,
long, long, long *));
const char * cgen_parse_unsigned_integer PARAMS ((const char **, int,
unsigned long, unsigned long,
unsigned long *));
const char * cgen_parse_address PARAMS ((const char **, int,
int, long *));
const char * cgen_parse_address PARAMS ((const char **, int, int,
enum cgen_parse_operand_result *,
long *));
const char * cgen_validate_signed_integer PARAMS ((long, long, long));
const char * cgen_validate_unsigned_integer PARAMS ((unsigned long,
unsigned long,
@ -406,27 +441,33 @@ const char * cgen_validate_unsigned_integer PARAMS ((unsigned long,
#define CGEN_MAX_OPERAND_ATTRS 1
#endif
typedef struct cgen_operand {
/* For debugging. */
typedef struct {
/* Name as it appears in the syntax string. */
char *name;
/* Bit position (msb of first byte = bit 0).
This is just a hint, and may be unused in more complex operands.
May be unused for a modifier. */
unsigned char start;
/* The number of bits in the operand.
This is just a hint, and may be unused in more complex operands.
May be unused for a modifier. */
unsigned char length;
/* Attributes. */
CGEN_ATTR_TYPE (CGEN_MAX_OPERAND_ATTRS) attrs;
#define CGEN_OPERAND_ATTRS(operand) (&(operand)->attrs)
#if 0 /* ??? Interesting idea but relocs tend to get too complicated for
simple table lookups to work. */
#if 0 /* ??? Interesting idea but relocs tend to get too complicated,
and ABI dependent, for simple table lookups to work. */
/* Ideally this would be the internal (external?) reloc type. */
int reloc_type;
#endif
/* Attributes.
This should, but technically needn't, appear last. It is a variable sized
array in that one architecture may have 1 nonbool attribute and another
may have more. Having this last means the non-architecture specific code
needn't care, now or tomorrow. */
CGEN_ATTR_TYPE (CGEN_MAX_OPERAND_ATTRS) attrs;
#define CGEN_OPERAND_ATTRS(operand) (&(operand)->attrs)
} CGEN_OPERAND;
/* Return value of attribute ATTR in OPERAND. */
@ -443,41 +484,132 @@ enum cgen_operand_type;
#define CGEN_OPERAND_TYPE(operand) ((enum cgen_operand_type) CGEN_OPERAND_INDEX (operand))
#define CGEN_OPERAND_ENTRY(n) (& CGEN_SYM (operand_table) [n])
/* Syntax string.
Each insn format and subexpression has one of these.
The syntax "string" consists of characters (n > 0 && n < 128), and operand
values (n >= 128), and is terminated by 0. Operand values are 128 + index
into the operand table. The operand table doesn't exist in C, per se, as
the data is recorded in the parse/insert/extract/print switch statements. */
#ifndef CGEN_MAX_SYNTAX_BYTES
#define CGEN_MAX_SYNTAX_BYTES 16
#endif
typedef struct {
unsigned char syntax[CGEN_MAX_SYNTAX_BYTES];
} CGEN_SYNTAX;
#define CGEN_SYNTAX_STRING(syn) (syn->syntax)
#define CGEN_SYNTAX_CHAR_P(c) ((c) < 128)
#define CGEN_SYNTAX_CHAR(c) (c)
#define CGEN_SYNTAX_FIELD(c) ((c) - 128)
/* ??? I can't currently think of any case where the mnemonic doesn't come
first [and if one ever doesn't building the hash tables will be tricky].
However, we treat mnemonics as just another operand of the instruction.
A value of 1 means "this is where the mnemonic appears". 1 isn't
special other than it's a non-printable ASCII char. */
#define CGEN_SYNTAX_MNEMONIC_P(ch) ((ch) == 1)
/* Instruction formats.
Instructions are grouped by format. Associated with an instruction is its
format. Each opcode table entry contains a pointer into the format table.
This cuts down on the size of the opcode table as there are relatively few
formats compared with the number of instructions. */
typedef struct {
/* Length that MASK and VALUE have been calculated to
[VALUE is recorded elsewhere].
Normally it is CGEN_BASE_INSN_BITSIZE. On [V]LIW architectures where
the base insn size may be larger than the size of an insn, this field is
less than CGEN_BASE_INSN_BITSIZE. */
unsigned char mask_length;
/* Total length of instruction. */
unsigned char length;
/* Mask to apply to the first BASE_LENGTH bits.
Each insn's value is stored with the insn.
The first step in recognizing an insn for disassembly is
(opcode & mask) == value. */
unsigned int mask;
} CGEN_FORMAT;
/* This struct defines each entry in the instruction table. */
struct cgen_insn {
/* ??? Further table size reductions can be had by moving this element
either to the format table or to a separate table of its own. Not
sure this is desirable yet. */
struct cgen_base base;
/* Given a pointer to a cgen_insn struct, return a pointer to `base'. */
#define CGEN_INSN_BASE(insn) (&(insn)->base)
#define CGEN_INSN_ATTRS(insn) (&(insn)->base.attrs)
struct cgen_syntax syntax;
#define CGEN_INSN_SYNTAX(insn) (&(insn)->syntax)
#define CGEN_INSN_FMT(insn) ((insn)->syntax.fmt)
#define CGEN_INSN_BITSIZE(insn) ((insn)->syntax.length)
};
/* Name of entry (that distinguishes it from all other entries).
This is used, for example, in simulator profiling results. */
/* ??? If mnemonics have operands, try to print full mnemonic. */
const char *name;
#define CGEN_INSN_NAME(insn) ((insn)->name)
/* Mnemonic. This is used when parsing and printing the insn.
In the case of insns that have operands on the mnemonics, this is
only the constant part. E.g. for conditional execution of an `add' insn,
where the full mnemonic is addeq, addne, etc., this is only "add". */
const char *mnemonic;
#define CGEN_INSN_MNEMONIC(insn) ((insn)->mnemonic)
/* Syntax string.
For now this only points to CGEN_SYNTAX elements, but it can point
to other things (e.g. something different for macros?). */
const CGEN_SYNTAX *syntax;
#define CGEN_INSN_SYNTAX(insn) ((CGEN_SYNTAX *) (insn)->syntax)
/* Format entry.
For now this only points to CGEN_FORMAT elements, but it can point
to other things (e.g. something different for macros?). */
const CGEN_FORMAT *format;
#define CGEN_INSN_MASK_BITSIZE(insn) (((CGEN_FORMAT *) (insn)->format)->mask_length)
#define CGEN_INSN_BITSIZE(insn) (((CGEN_FORMAT *) (insn)->format)->length)
/* Instruction opcode value. */
unsigned int value;
#define CGEN_INSN_VALUE(insn) ((insn)->value)
#define CGEN_INSN_MASK(insn) (((CGEN_FORMAT *) (insn)->format)->mask)
/* Attributes.
This must appear last. It is a variable sized array in that one
architecture may have 1 nonbool attribute and another may have more.
Having this last means the non-architecture specific code needn't
care. */
CGEN_ATTR_TYPE (CGEN_MAX_INSN_ATTRS) attrs;
#define CGEN_INSN_ATTRS(insn) (&(insn)->attrs)
/* Return value of attribute ATTR in INSN. */
#define CGEN_INSN_ATTR(insn, attr) \
CGEN_ATTR_VALUE (insn, CGEN_INSN_ATTRS (insn), attr)
};
/* Instruction lists.
This is used for adding new entries and for creating the hash lists. */
typedef struct cgen_insn_list {
struct cgen_insn_list *next;
const struct cgen_insn *insn;
const CGEN_INSN *insn;
} CGEN_INSN_LIST;
/* The table of instructions. */
typedef struct cgen_insn_table {
typedef struct {
/* Pointer to initial [compiled in] entries. */
const struct cgen_insn *init_entries;
const CGEN_INSN *init_entries;
/* Size of an entry (since the attribute member is variable sized). */
unsigned int entry_size;
/* Number of entries in `init_entries', including trailing NULL entry. */
unsigned int num_init_entries;
/* Values added at runtime. */
struct cgen_insn_list *new_entries;
CGEN_INSN_LIST *new_entries;
/* Assembler hash function. */
unsigned int (*asm_hash) PARAMS ((const char *));
/* Number of entries in assembler hash table. */
@ -498,7 +630,7 @@ extern const CGEN_INSN CGEN_SYM (insn_table_entries)[];
/* Return number of instructions. This includes any added at runtime. */
int cgen_insn_count PARAMS (());
int cgen_insn_count PARAMS ((void));
/* The assembler insn table is hashed based on some function of the mnemonic
(the actually hashing done is up to the target, but we provide a few
@ -541,7 +673,7 @@ CGEN_INSN_LIST * cgen_dis_lookup_insn PARAMS ((const char *, unsigned long));
/* Top level structures and functions. */
typedef struct cgen_opcode_data {
typedef struct {
CGEN_HW_ENTRY *hw_list;
/*CGEN_OPERAND_TABLE *operand_table; - FIXME:wip */
CGEN_INSN_TABLE *insn_table;
@ -580,12 +712,12 @@ void CGEN_SYM (init_extract) PARAMS ((void));
const struct cgen_insn *
CGEN_SYM (assemble_insn) PARAMS ((const char *, struct cgen_fields *,
cgen_insn_t *, char **));
int CGEN_SYM (insn_supported) PARAMS ((const struct cgen_syntax *));
#if 0 /* old */
int CGEN_SYM (insn_supported) PARAMS ((const struct cgen_insn *));
int CGEN_SYM (opval_supported) PARAMS ((const struct cgen_opval *));
#endif
extern const struct cgen_keyword CGEN_SYM (operand_mach);
extern const CGEN_KEYWORD CGEN_SYM (operand_mach);
int CGEN_SYM (get_mach) PARAMS ((const char *));
CGEN_INLINE void
@ -608,63 +740,5 @@ extern cgen_print_fn CGEN_SYM (print_insn);
/* Read in a cpu description file. */
const char * cgen_read_cpu_file PARAMS ((const char *));
/* Assembler interface.
The interface to the assembler is intended to be clean in the sense that
libopcodes.a is a standalone entity and could be used with any assembler.
Not that one would necessarily want to do that but rather that it helps
keep a clean interface. The interface will obviously be slanted towards
GAS, but at least it's a start.
Parsing is controlled by the assembler which calls
CGEN_SYM (assemble_insn). If it can parse and build the entire insn
it doesn't call back to the assembler. If it needs/wants to call back
to the assembler, (*cgen_asm_parse_operand_fn) is called which can either
- return a number to be inserted in the insn
- return a "register" value to be inserted
(the register might not be a register per pe)
- queue the argument and return a marker saying the expression has been
queued (eg: a fix-up)
- return an error message indicating the expression wasn't recognizable
The result is an error message or NULL for success.
The parsed value is stored in the bfd_vma *. */
enum cgen_asm_result {
CGEN_ASM_NUMBER, CGEN_ASM_REGISTER, CGEN_ASM_QUEUED, CGEN_ASM_ERROR
};
/* Don't require bfd.h unnecessarily. */
#ifdef BFD_VERSION
extern const char * (*cgen_asm_parse_operand_fn)
PARAMS ((const char **, int, int, enum cgen_asm_result *, bfd_vma *));
#endif
/* These are GAS specific. They're not here as part of the interface,
but rather that we need to put them somewhere. */
/* Call this for each insn to initialize the assembler callback interface. */
void cgen_asm_init_parse PARAMS ((void));
/* Don't require bfd.h unnecessarily. */
#ifdef BFD_VERSION
/* The result is an error message or NULL for success.
The parsed value is stored in the bfd_vma *. */
const char *cgen_asm_parse_operand PARAMS ((const char **, int, int,
enum cgen_asm_result *,
bfd_vma *));
#endif
/* Add a register to the assembler's hash table.
This makes lets GAS parse registers for us.
??? This isn't currently used, but it could be in the future. */
void cgen_asm_record_register PARAMS ((char *, int));
/* After CGEN_SYM (assemble_insn) is done, this is called to
output the insn and record any fixups. */
void cgen_asm_finish_insn PARAMS ((const struct cgen_insn *, cgen_insn_t *,
unsigned int));
#endif /* CGEN_H */