From 030f419b085c2b14a465c46be5229a35fe124cab Mon Sep 17 00:00:00 2001 From: Doug Evans Date: Mon, 27 Apr 1998 17:31:38 +0000 Subject: [PATCH] * cgen.h (CGEN_ATTR_TYPE): Delete `const', moved to uses. (cgen_asm_finish_insn): Update prototype. (cgen_insn): New members num, data. (CGEN_INSN_TABLE): Members asm_hash, asm_hash_table_size, dis_hash, dis_hash_table_size moved to ... (CGEN_OPCODE_TABLE). Here. Renamed from CGEN_OPCODE_DATA. All uses updated. New members asm_hash_p, dis_hash_p. (CGEN_MINSN_EXPANSION): New struct. (cgen_expand_macro_insn): Declare. (cgen_macro_insn_count): Declare. (get_insn_operands): Update prototype. (lookup_get_insn_operands): Declare. --- include/opcode/ChangeLog | 15 +++ include/opcode/cgen.h | 300 ++++++++++++++++++++++++++++++----------------- 2 files changed, 206 insertions(+), 109 deletions(-) diff --git a/include/opcode/ChangeLog b/include/opcode/ChangeLog index c8a7789..b18bc0b 100644 --- a/include/opcode/ChangeLog +++ b/include/opcode/ChangeLog @@ -1,3 +1,18 @@ +Mon Apr 27 10:13:11 1998 Doug Evans + + * cgen.h (CGEN_ATTR_TYPE): Delete `const', moved to uses. + (cgen_asm_finish_insn): Update prototype. + (cgen_insn): New members num, data. + (CGEN_INSN_TABLE): Members asm_hash, asm_hash_table_size, + dis_hash, dis_hash_table_size moved to ... + (CGEN_OPCODE_TABLE). Here. Renamed from CGEN_OPCODE_DATA. + All uses updated. New members asm_hash_p, dis_hash_p. + (CGEN_MINSN_EXPANSION): New struct. + (cgen_expand_macro_insn): Declare. + (cgen_macro_insn_count): Declare. + (get_insn_operands): Update prototype. + (lookup_get_insn_operands): Declare. + Tue Apr 21 17:11:32 1998 Alan Modra * i386.h (i386_optab): Change iclrKludge and imulKludge to diff --git a/include/opcode/cgen.h b/include/opcode/cgen.h index 5043c4c..10c9724 100644 --- a/include/opcode/cgen.h +++ b/include/opcode/cgen.h @@ -87,13 +87,17 @@ typedef struct nonbool: values of non-boolean attributes There is a maximum of 32 attributes total. */ #define CGEN_ATTR_TYPE(n) \ -const struct { unsigned char num_nonbools; \ - unsigned int bool; \ - unsigned int nonbool[(n) ? (n) : 1]; } +struct { unsigned char num_nonbools; \ + unsigned int bool; \ + unsigned int nonbool[(n) ? (n) : 1]; } /* Given an attribute number, return its mask. */ #define CGEN_ATTR_MASK(attr) (1 << (attr)) +/* Return the value of boolean attribute ATTR in ATTRS. */ +#define CGEN_BOOL_ATTR(attrs, attr) \ +((CGEN_ATTR_MASK (attr) & (attrs)) != 0) + /* Return value of attribute ATTR in ATTR_TABLE for OBJ. OBJ is a pointer to the entity that has the attributes. It's not used at present but is reserved for future purposes. */ @@ -108,14 +112,14 @@ const struct { unsigned char num_nonbools; \ typedef struct { const char * name; - int value; + int value; } CGEN_ATTR_ENTRY; /* For each domain (fld,operand,insn), list of attributes. */ typedef struct { - const char * name; + const char * name; /* NULL for boolean attributes. */ const CGEN_ATTR_ENTRY * vals; } CGEN_ATTR_TABLE; @@ -231,7 +235,9 @@ struct cgen_base /* Indices into the handler tables. We could use pointers here instead, but in the case of the insn table, 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). */ + 0 means use the default (what the default is is up to the code). + Using indices also keeps assembler code out of the disassembler and + vice versa. */ unsigned char parse, insert, extract, print; }; @@ -284,7 +290,7 @@ extern const char * (*cgen_parse_operand_fn) #endif /* Called before trying to match a table entry with the insn. */ -void cgen_init_parse_operand PARAMS ((void)); +extern void cgen_init_parse_operand PARAMS ((void)); /* Called from -asm.c to initialize operand parsing. */ @@ -292,33 +298,34 @@ void cgen_init_parse_operand PARAMS ((void)); 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)); +extern 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 *)); +extern const char * cgen_parse_operand + PARAMS ((enum cgen_parse_operand_type, + const char **, int, int, + enum cgen_parse_operand_result *, + bfd_vma *)); #endif -void cgen_save_fixups PARAMS ((void)); -void cgen_restore_fixups PARAMS ((void)); -void cgen_swap_fixups PARAMS ((void)); +extern void cgen_save_fixups PARAMS ((void)); +extern void cgen_restore_fixups PARAMS ((void)); +extern void cgen_swap_fixups PARAMS ((void)); /* 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)); +extern 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. The address of the assembled instruction is returned in case it is needed by the caller. */ -char * cgen_asm_finish_insn PARAMS ((const struct cgen_insn *, cgen_insn_t *, - unsigned int)); +extern char * cgen_asm_finish_insn PARAMS ((const struct cgen_insn *, + cgen_insn_t *, unsigned int, int)); /* Operand values (keywords, integers, symbols, etc.) */ @@ -335,14 +342,14 @@ typedef struct cgen_hw_entry { /* The type of this entry, one of `enum hw_type'. This is an int and not the enum as the latter may not be declared yet. */ - int type; + int type; const struct cgen_hw_entry * next; - char * name; - enum cgen_asm_type asm_type; - PTR asm_data; + char * name; + enum cgen_asm_type asm_type; + PTR asm_data; } CGEN_HW_ENTRY; -const CGEN_HW_ENTRY * cgen_hw_lookup PARAMS ((const char *)); +extern const CGEN_HW_ENTRY * cgen_hw_lookup PARAMS ((const char *)); /* This struct is used to describe things like register names, etc. */ @@ -367,7 +374,7 @@ typedef struct cgen_keyword_entry #ifndef CGEN_KEYWORD_NBOOL_ATTRS #define CGEN_KEYWORD_NBOOL_ATTRS 1 #endif - CGEN_ATTR_TYPE (CGEN_KEYWORD_NBOOL_ATTRS) attrs; + const CGEN_ATTR_TYPE (CGEN_KEYWORD_NBOOL_ATTRS) attrs; /* Next name hash table entry. */ struct cgen_keyword_entry *next_name; @@ -436,19 +443,20 @@ const CGEN_KEYWORD_ENTRY *cgen_keyword_search_next /* 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 **, - CGEN_KEYWORD *, - long *)); -const char * cgen_parse_signed_integer PARAMS ((const char **, int, long *)); -const char * cgen_parse_unsigned_integer PARAMS ((const char **, int, - unsigned 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, - unsigned long)); +extern const char * cgen_parse_keyword PARAMS ((const char **, + CGEN_KEYWORD *, + long *)); +extern const char * cgen_parse_signed_integer PARAMS ((const char **, int, + long *)); +extern const char * cgen_parse_unsigned_integer PARAMS ((const char **, int, + unsigned long *)); +extern const char * cgen_parse_address PARAMS ((const char **, int, int, + enum cgen_parse_operand_result *, + long *)); +extern const char * cgen_validate_signed_integer PARAMS ((long, long, long)); +extern const char * cgen_validate_unsigned_integer PARAMS ((unsigned long, + unsigned long, + unsigned long)); /* Operand modes. */ @@ -510,7 +518,7 @@ typedef struct cgen_operand #ifndef CGEN_OPERAND_NBOOL_ATTRS #define CGEN_OPERAND_NBOOL_ATTRS 1 #endif - CGEN_ATTR_TYPE (CGEN_OPERAND_NBOOL_ATTRS) attrs; + const CGEN_ATTR_TYPE (CGEN_OPERAND_NBOOL_ATTRS) attrs; #define CGEN_OPERAND_ATTRS(operand) (&(operand)->attrs) } CGEN_OPERAND; @@ -639,14 +647,17 @@ typedef struct 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. */ + /* This field is an array of functions that operand on this entry. */ struct cgen_base base; - -/* Given a pointer to a cgen_insn struct, return a pointer to `base'. */ #define CGEN_INSN_BASE(insn) (&(insn)->base) + /* Each real instruction is enumerated. This is used, for example, to do + insn profiling in the simulator. + Macro-insns are not enumerated. The simulator doesn't use them and there + is currently no other need for it. */ + int num; +#define CGEN_INSN_NUM(insn) ((insn)->num) + /* 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. */ @@ -674,10 +685,16 @@ struct cgen_insn #define CGEN_INSN_VALUE(insn) ((insn)->value) #define CGEN_INSN_MASK(insn) ((insn)->format.mask) - /* Pointer to NULL entry terminated table of operands used, - or NULL if none. */ - const CGEN_OPERAND_INSTANCE *operands; -#define CGEN_INSN_OPERANDS(insn) ((insn)->operands) + /* Opaque pointer to "subclass" specific data. + In the case of real insns this points to a NULL entry terminated + table of operands used, or NULL if none. + In the case of macro insns this points to data to control the expansion. + ??? I'd rather not get carried away and lay things out with pedantic + purity right now. Sure, other fields might better be tucked away in + `data'. Not now. */ + PTR data; +#define CGEN_INSN_DATA(insn) ((insn)->data) +#define CGEN_INSN_OPERANDS(insn) ((CGEN_OPERAND_INSTANCE *) (insn)->data) /* Attributes. This must appear last. It is a variable sized array in that one @@ -687,7 +704,7 @@ struct cgen_insn #ifndef CGEN_INSN_NBOOL_ATTRS #define CGEN_INSN_NBOOL_ATTRS 1 #endif - CGEN_ATTR_TYPE (CGEN_INSN_NBOOL_ATTRS) attrs; + const CGEN_ATTR_TYPE (CGEN_INSN_NBOOL_ATTRS) attrs; #define CGEN_INSN_ATTRS(insn) (&(insn)->attrs) /* Return value of attribute ATTR in INSN. */ #define CGEN_INSN_ATTR(insn, attr) \ @@ -718,82 +735,147 @@ typedef struct /* Values added at runtime. */ CGEN_INSN_LIST * new_entries; - - /* Assembler hash function. */ - unsigned int (* asm_hash) PARAMS ((const char *)); - - /* Number of entries in assembler hash table. */ - unsigned int asm_hash_table_size; - - /* Disassembler hash function. */ - unsigned int (* dis_hash) PARAMS ((const char *, unsigned long)); - - /* Number of entries in disassembler hash table. */ - unsigned int dis_hash_table_size; } CGEN_INSN_TABLE; -/* ??? This is currently used by the simulator. - We want this to be fast and the simulator currently doesn't handle - runtime added instructions so this is ok. An alternative would be to - store the index in the table. */ +/* ??? This is currently used by the simulator. */ extern const CGEN_INSN CGEN_SYM (insn_table_entries)[]; -#define CGEN_INSN_INDEX(insn) ((int) ((insn) - CGEN_SYM (insn_table_entries))) -#define CGEN_INSN_ENTRY(n) (& CGEN_SYM (insn_table_entries) [n]) /* Return number of instructions. This includes any added at runtime. */ -int cgen_insn_count PARAMS ((void)); - +extern int cgen_insn_count PARAMS ((void)); + +/* Macro instructions. + Macro insns aren't real insns, they map to one or more real insns. + E.g. An architecture's "nop" insn may actually be an "mv r0,r0" or + some such. + + Macro insns can expand to nothing (e.g. a nop that is optimized away). + This is useful in multi-insn macros that build a constant in a register. + Of course this isn't the default behaviour and must be explicitly enabled. + + Assembly of macro-insns is relatively straightforward. Disassembly isn't. + However, disassembly of at least some kinds of macro insns is important + in order that the disassembled code preserve the readability of the original + insn. What is attempted here is to disassemble all "simple" macro-insns, + where "simple" is currently defined to mean "expands to one real insn". + + Simple macro-insns are handled specially. They are emitted as ALIAS's + of real insns. This simplifies their handling since there's usually more + of them than any other kind of macro-insn, and proper disassembly of them + falls out for free. */ + +/* For each macro-insn there may be multiple expansion possibilities, + depending on the arguments. This structure is accessed via the `data' + member of CGEN_INSN. */ + +typedef struct cgen_minsn_expansion { + /* Function to do the expansion. + If the expansion fails (e.g. "no match") NULL is returned. + Space for the expansion is obtained with malloc. + It is up to the caller to free it. */ + const char * (* fn) PARAMS ((const struct cgen_minsn_expansion *, + const char *, const char **, int *, CGEN_OPERAND **)); +#define CGEN_MIEXPN_FN(ex) ((ex)->fn) + + /* Instruction(s) the macro expands to. + The format of STR is defined by FN. + It is typically the assembly code of the real insn, but it could also be + the original Scheme expression or a tokenized form of it (with FN being + an appropriate interpreter). */ + const char * str; +#define CGEN_MIEXPN_STR(ex) ((ex)->str) +} CGEN_MINSN_EXPANSION; + +/* Normal expander. + When supported, this function will convert the input string to another + string and the parser will be invoked recursively. The output string + may contain further macro invocations. */ + +extern const char * cgen_expand_macro_insn + PARAMS ((const struct cgen_minsn_expansion *, + const char *, const char **, int *, CGEN_OPERAND **)); + /* 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 - examples like the first letter or a function of the entire mnemonic). - The index of each entry is the index of the corresponding table entry. - The value of each entry is the index of the next entry, with a 0 - terminating (thus the first entry is reserved). */ + examples like the first letter or a function of the entire mnemonic). */ + +#ifndef CGEN_ASM_HASH_P +#define CGEN_ASM_HASH_P(insn) 1 +#endif +/* INSN is the CGEN_INSN entry when building the hash table and NULL + when looking up the insn during assembly. */ #ifndef CGEN_ASM_HASH -#ifdef CGEN_MNEMONIC_OPERANDS #define CGEN_ASM_HASH_SIZE 127 -#define CGEN_ASM_HASH(string) (*(unsigned char *) (string) % CGEN_ASM_HASH_SIZE) +#ifdef CGEN_MNEMONIC_OPERANDS +#define CGEN_ASM_HASH(mnem) (*(unsigned char *) (mnem) % CGEN_ASM_HASH_SIZE) #else -#define CGEN_ASM_HASH_SIZE 128 -#define CGEN_ASM_HASH(string) (*(unsigned char *) (string) % CGEN_ASM_HASH_SIZE) /*FIXME*/ +#define CGEN_ASM_HASH(mnem) (*(unsigned char *) (mnem) % CGEN_ASM_HASH_SIZE) /*FIXME*/ #endif #endif -unsigned int CGEN_SYM (asm_hash_insn) PARAMS ((const char *)); -CGEN_INSN_LIST * cgen_asm_lookup_insn PARAMS ((const char *)); -#define CGEN_ASM_LOOKUP_INSN(insn) cgen_asm_lookup_insn (insn) +extern CGEN_INSN_LIST * cgen_asm_lookup_insn PARAMS ((const char *)); +#define CGEN_ASM_LOOKUP_INSN(string) cgen_asm_lookup_insn (string) #define CGEN_ASM_NEXT_INSN(insn) ((insn)->next) /* The disassembler insn table is hashed based on some function of machine instruction (the actually hashing done is up to the target). */ +#ifndef CGEN_DIS_HASH_P +#define CGEN_DIS_HASH_P(insn) 1 +#endif + /* It doesn't make much sense to provide a default here, but while this is under development we do. + INSN is the CGEN_INSN entry when building the hash table and NULL + when looking up the insn during assembly. BUFFER is a pointer to the bytes of the insn. - INSN is the first CGEN_BASE_INSN_SIZE bytes as an int in host order. */ + VALUE is the first CGEN_BASE_INSN_SIZE bytes as an int in host order. */ #ifndef CGEN_DIS_HASH #define CGEN_DIS_HASH_SIZE 256 -#define CGEN_DIS_HASH(buffer, insn) (*(unsigned char *) (buffer)) +#define CGEN_DIS_HASH(buffer, value) (*(unsigned char *) (buffer)) #endif -unsigned int CGEN_SYM (dis_hash_insn) PARAMS ((const char *, unsigned long)); -CGEN_INSN_LIST * cgen_dis_lookup_insn PARAMS ((const char *, unsigned long)); -#define CGEN_DIS_LOOKUP_INSN(buf, insn) cgen_dis_lookup_insn (buf, insn) +extern CGEN_INSN_LIST * cgen_dis_lookup_insn PARAMS ((const char *, + unsigned long)); +#define CGEN_DIS_LOOKUP_INSN(buf, value) cgen_dis_lookup_insn ((buf), (value)) #define CGEN_DIS_NEXT_INSN(insn) ((insn)->next) /* Top level structures and functions. */ typedef struct { - const CGEN_HW_ENTRY * hw_list; + const CGEN_HW_ENTRY * hw_list; + /*CGEN_OPERAND_TABLE * operand_table; - FIXME:wip */ - CGEN_INSN_TABLE * insn_table; -} CGEN_OPCODE_DATA; + + CGEN_INSN_TABLE * insn_table; + + /* Macro instructions are defined separately and are combined with real + insns during hash table computation. */ + CGEN_INSN_TABLE * macro_insn_table; + + /* Return non-zero if insn should be added to hash table. */ + int (* asm_hash_p) PARAMS ((const CGEN_INSN *)); + + /* Assembler hash function. */ + unsigned int (* asm_hash) PARAMS ((const char *)); + + /* Number of entries in assembler hash table. */ + unsigned int asm_hash_table_size; + + /* Return non-zero if insn should be added to hash table. */ + int (* dis_hash_p) PARAMS ((const CGEN_INSN *)); + + /* Disassembler hash function. */ + unsigned int (* dis_hash) PARAMS ((const char *, unsigned long)); + + /* Number of entries in disassembler hash table. */ + unsigned int dis_hash_table_size; +} CGEN_OPCODE_TABLE; /* Each CPU has one of these. */ -extern CGEN_OPCODE_DATA CGEN_SYM (opcode_data); +extern const CGEN_OPCODE_TABLE CGEN_SYM (opcode_table); /* Global state access macros. Some of these are tucked away and accessed with cover fns. @@ -808,42 +890,42 @@ extern enum cgen_endian cgen_current_endian; /* Prototypes of major functions. */ /* Set the current cpu (+ mach number, endian, etc.). */ -void cgen_set_cpu PARAMS ((CGEN_OPCODE_DATA *, int, enum cgen_endian)); +extern void cgen_set_cpu PARAMS ((const CGEN_OPCODE_TABLE *, int, + enum cgen_endian)); /* Initialize the assembler, disassembler. */ -void cgen_asm_init PARAMS ((void)); -void cgen_dis_init PARAMS ((void)); +extern void cgen_asm_init PARAMS ((void)); +extern void cgen_dis_init PARAMS ((void)); /* `init_tables' must be called before `xxx_supported'. */ -void CGEN_SYM (init_tables) PARAMS ((int)); -void CGEN_SYM (init_asm) PARAMS ((int, enum cgen_endian)); -void CGEN_SYM (init_dis) PARAMS ((int, enum cgen_endian)); -void CGEN_SYM (init_parse) PARAMS ((void)); -void CGEN_SYM (init_print) PARAMS ((void)); -void CGEN_SYM (init_insert) PARAMS ((void)); -void CGEN_SYM (init_extract) PARAMS ((void)); +extern void CGEN_SYM (init_tables) PARAMS ((int)); +extern void CGEN_SYM (init_asm) PARAMS ((int, enum cgen_endian)); +extern void CGEN_SYM (init_dis) PARAMS ((int, enum cgen_endian)); /* FIXME: This prototype is wrong ifndef CGEN_INT_INSN. Furthermore, ifdef CGEN_INT_INSN, the insn is created in target byte order (in which case why use int's at all). Perhaps replace cgen_insn_t * with char *? */ -const struct cgen_insn * +extern const struct cgen_insn * CGEN_SYM (assemble_insn) PARAMS ((const char *, CGEN_FIELDS *, cgen_insn_t *, char **)); #if 0 /* old */ -int CGEN_SYM (insn_supported) PARAMS ((const struct cgen_insn *)); -int CGEN_SYM (opval_supported) PARAMS ((const struct cgen_opval *)); +extern int CGEN_SYM (insn_supported) PARAMS ((const struct cgen_insn *)); +extern int CGEN_SYM (opval_supported) PARAMS ((const struct cgen_opval *)); #endif extern const CGEN_KEYWORD CGEN_SYM (operand_mach); -int CGEN_SYM (get_mach) PARAMS ((const char *)); +extern int CGEN_SYM (get_mach) PARAMS ((const char *)); -const CGEN_INSN * -CGEN_SYM (get_insn_operands) PARAMS ((const CGEN_INSN *, cgen_insn_t, - int, int *)); -const CGEN_INSN * +extern const CGEN_INSN * CGEN_SYM (lookup_insn) PARAMS ((const CGEN_INSN *, cgen_insn_t, int, CGEN_FIELDS *, int)); +extern void +CGEN_SYM (get_insn_operands) PARAMS ((const CGEN_INSN *, const CGEN_FIELDS *, + int *)); +extern const CGEN_INSN * +CGEN_SYM (lookup_get_insn_operands) PARAMS ((const CGEN_INSN *, cgen_insn_t, + int, int *)); CGEN_INLINE void CGEN_SYM (put_operand) PARAMS ((int, const long *, @@ -851,10 +933,10 @@ CGEN_SYM (put_operand) PARAMS ((int, const long *, CGEN_INLINE long CGEN_SYM (get_operand) PARAMS ((int, const CGEN_FIELDS *)); -const char * +extern const char * CGEN_SYM (parse_operand) PARAMS ((int, const char **, CGEN_FIELDS *)); -const char * +extern const char * CGEN_SYM (insert_operand) PARAMS ((int, CGEN_FIELDS *, char *)); /* Default insn parser, printer. */ @@ -864,6 +946,6 @@ extern cgen_extract_fn CGEN_SYM (extract_insn); extern cgen_print_fn CGEN_SYM (print_insn); /* Read in a cpu description file. */ -const char * cgen_read_cpu_file PARAMS ((const char *)); +extern const char * cgen_read_cpu_file PARAMS ((const char *)); #endif /* CGEN_H */ -- 2.7.4