From mboxrd@z Thu Jan 1 00:00:00 1970 From: Greg McGary To: cgen@sourceware.cygnus.com Subject: PATCH: string-expansion macros Date: Fri, 02 Mar 2001 15:59:00 -0000 Message-id: <200103022358.QAA31874@kayak.mcgary.org> X-SW-Source: 2001-q1/msg00142.html I have been sitting on this for almost 8 weeks now, waiting for some spare time to submit it. Well, I still have no spare time, but can't in good conscience delay any longer. I have several weeks experience using it in my port, and it works fine. A possibly controversial change is this: * opcodes/cgen-asm.c (build_asm_hash_table): Try to match hard insns before macros & aliases. I'd like to know why the old code tried to match macros before hard insns? The reason I need to try hard insns before macros is that for my MIPS-like port, string macros catch cases that can't be handled by one insn, and implement a "virtual insn" that do things in 2 or 3 hard insns. E.g., hard insn for set-register accepts a 16-bit immediate operand. As a fallback, I have a string-macro that accepts a 32-bit immediate and expands to two hard insns to set upper and lower 16-bits. If the macro were tried first, a small constant actual operand would certainly match the constraint of a 32-bit operand and the 2-insn macro would expand before we tried the hard insn which should match. The only way that trying macros before hard insns could work for me is with a more sophisticated 32-bit operand constraint that only matches quantities that don't fit in 16 bits. As an example of use, here are the "mov" insns for copying an immediate into a register: (dnmi moviwu "Move Immediate Word Unsigned" (NO-DIS) "mov $dest2,$uimm32" ("movhi %0,%1@h" "or %0,%1@l")) (dnmi moviws "Move Immediate Word Signed" (NO-DIS) "mov $dest2,$simm32" ("movhi %0 %1@h" "or %0,%1@l")) Here's a double-word add macro. (I defined general register keywords with `_next' suffix for making register pairs: $2 is register 2, $2_next is register 3.) (dnmi daddu "Add Double-word Unsigned" (NO-DIS) "daddu $dest,$src1,$src2" ("addu %0,%1,%2" "setltu %0_next,%0,%1" "addu %0_next,%0_next,%1_next" "addu %0_next,%0_next,%2_next")) Comments? Greg This ChangeLog is unified. At checkin time, I'll split it up among the ChangeLog files in each of the component directories. 2001-03-02 Greg McGary * cgen/attr.scm (attr-builtin!): Add MACRO & STRING * cgen/minsn.scm (-minsn-parse-expansion): Allow list of strings. (-minsn-parse): Likewise. (define-full-minsn): Affix MACRO attr and STRING or ALIAS attr depending on type of expansion. * cgen/opc-itab.scm (-gen-ifield-decls) [cgen_fields]: New members op_starts and op_lengths. (opc-insert-handlers): New handler: insn-macro-string. (-gen-insn-opcode-entry): Wrap curlies around field which is now a union. (-gen-minsn-table-entry): Print proper string-macro entry. (-gen-minsn-macro-string-expansion): New function. (-gen-minsn-opcode-entry): Handle STRING macros. (-gen-macro-insn-table): Invert condition. Test for STRING explicitly. * gas/read.c (read_a_source_file): Repackage macro-listing code. Handle CGEN string macro expansion. (maybe_print_macro_listing): New function. * gas/tc.h (md_assemble): Conditionalize return value on MD_ASSEMBLE_MACRO. * include/opcode/cgen.h (CGEN_OPCODE): wrap union around member `format', and add member `string' alongside. (CGEN_OPCODE_FORMAT): Traverse enclosing union. (CGEN_OPCODE_MACRO_STRING, CGEN_INSN_MACRO_STRING): New macros. * opcodes/cgen-asm.c (build_asm_hash_table): Try to match hard insns before macros & aliases. * opcodes/cgen-asm.in (parse_insn_normal): Remember starts & lengths of actual operands. * opcodes/cgen-ibld.in (insert_insn_normal): Return NULL if no errors. (insert_insn_macro_string): New function. Index: cgen/attr.scm =================================================================== RCS file: /cvs/src/src/cgen/attr.scm,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 attr.scm --- attr.scm 2000/07/28 04:11:52 1.1.1.1 +++ attr.scm 2001/03/02 23:25:24 @@ -1,5 +1,5 @@ ; Attributes. -; Copyright (C) 2000 Red Hat, Inc. +; Copyright (C) 2000, 2001 Red Hat, Inc. ; This file is part of CGEN. ; See file COPYING.CGEN for details. @@ -893,11 +893,20 @@ Define an attribute, name/value pair lis (define-attr '(for keyword) '(type boolean) '(name PRIVATE)) ; Attributes requiring fixed indices. - ; ALIAS is used for instructions that are aliases of more general insns. - ; ALIAS insns are ignored by the simulator. + ; MACRO insns are ignored by the simulator. + ; ALIAS is a 1:1 renaming (possibly omitting operands) of a real insn + ; STRING is an expansion into which we insert textual representation + ; of operands and then reparse. + ; if neither ALIAS or STRING, expansion is a builder function. (define-attr '(for attr) '(type boolean) '(name INDEX) '(attrs META)) + (define-attr '(for insn) '(type boolean) '(name MACRO) + '(comment "insn expands into something else") + '(attrs INDEX)) (define-attr '(for insn) '(type boolean) '(name ALIAS) - '(comment "insn is an alias of another") + '(comment "insn is a macro that's a simple an alias of a real insn") + '(attrs INDEX)) + (define-attr '(for insn) '(type boolean) '(name STRING) + '(comment "insn is a macro that expands into a string to be reparsed") '(attrs INDEX)) *UNSPECIFIED* Index: cgen/minsn.scm =================================================================== RCS file: /cvs/src/src/cgen/minsn.scm,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 minsn.scm --- minsn.scm 2000/07/28 04:11:52 1.1.1.1 +++ minsn.scm 2001/03/02 23:25:24 @@ -1,5 +1,5 @@ ; Macro instruction definitions. -; Copyright (C) 2000 Red Hat, Inc. +; Copyright (C) 2000, 2001 Red Hat, Inc. ; This file is part of CGEN. ; See file COPYING.CGEN for details. @@ -18,7 +18,10 @@ ; description in the .cpu file. ; All arguments are in raw (non-evaluated) form. -; ??? At present we only support macros that are aliases of one real insn. +; ??? At present we only support macros that are +; 1) aliases of one real insn +; 2) and string-expansion. +; someday we might support a general insn builder mechanmsim as well. ; Object to describe a macro-insn. @@ -57,13 +60,15 @@ ) ; Parse a macro-insn expansion description. -; ??? At present we only support unconditional simple expansion. (define (-minsn-parse-expansion errtxt expn) - (if (not (form? expn)) - (parse-error errtxt "invalid macro expansion" expn)) - (if (not (eq? 'emit (car expn))) - (parse-error errtxt "invalid macro expansion, must be `(emit ...)'" expn)) + (cond ((null? expn) + (parse-error errtxt "empty macro expansion" expn)) + ((not (list? expn)) + (parse-error errtxt "invalid macro expansion" expn)) + ((not (or (eq? 'emit (car expn)) + (string? (car expn)))) + (parse-error errtxt "invalid macro expansion" expn))) expn ) @@ -76,26 +81,37 @@ (define (-minsn-parse errtxt name comment attrs syntax expansions) (logit 2 "Processing macro-insn " name " ...\n") - (if (not (list? expansions)) - (parse-error errtxt "invalid macro expansion list" expansions)) - - (let ((name (parse-name name errtxt)) - (atlist-obj (atlist-parse attrs "cgen_minsn" errtxt))) - - (if (keep-atlist? atlist-obj #f) - - (let ((result (make - name - (parse-comment comment errtxt) - atlist-obj - (parse-syntax syntax errtxt) - (map (lambda (e) (-minsn-parse-expansion errtxt e)) - expansions)))) - result) - - (begin - (logit 2 "Ignoring " name ".\n") - #f))) + (if (cond ((not (list? expansions)) + (parse-error errtxt "invalid macro expansion: not a list" expansions) + #f) + ((not (list? (car expansions))) + (parse-error errtxt "invalid macro expansion: not a list" expansions) + #f) + ((string? (caar expansions)) + (logit 2 "Parsing " name " as list-of-strings expansion.\n") + #t) + ((eq? 'emit (caar expansions)) + (logit 2 "Parsing " name " as emit expansion.\n") + #t) + (else + (logit 2 "Ignoring " name ": unknown expansion.\n") + #f)) + (let ((name (parse-name name errtxt)) + (atlist-obj (atlist-parse attrs "cgen_minsn" errtxt))) + + (if (keep-atlist? atlist-obj #f) + (let ((result (make + name + (parse-comment comment errtxt) + atlist-obj + (parse-syntax syntax errtxt) + (map (lambda (e) (-minsn-parse-expansion errtxt e)) + expansions)))) + result) + (begin + (logit 2 "Ignoring " name ".\n") + #f))) + #f) ) ; Read a macro-insn description @@ -152,7 +168,10 @@ (if (eq? APPLICATION 'SIMULATOR) #f ; don't waste time if simulator (let ((m (-minsn-parse "define-full-minsn" name comment - (cons 'ALIAS attrs) + (cons 'MACRO + (if (string? (car expansion)) + (cons 'STRING attrs) + (cons 'ALIAS attrs))) syntax (list expansion)))) (if m (current-minsn-add! m)) Index: cgen/opc-itab.scm =================================================================== RCS file: /cvs/src/src/cgen/opc-itab.scm,v retrieving revision 1.2 diff -u -p -r1.2 opc-itab.scm --- opc-itab.scm 2000/11/20 19:03:33 1.2 +++ opc-itab.scm 2001/03/02 23:25:25 @@ -1,5 +1,5 @@ ; Opcode table support. -; Copyright (C) 2000 Red Hat, Inc. +; Copyright (C) 2000, 2001 Red Hat, Inc. ; This file is part of CGEN. ; Append code here to be run before insn parsing/etc. @@ -47,6 +47,10 @@ "struct cgen_fields\n{\n" ; A special member `length' is used to record the length. " int length;\n" + ; Special members to hold operand strings for macro string expansion. + " const char *op_starts[10];\n" + " int op_lengths[10];\n" + " const char *macro_string_expansion;\n" (string-map gen-ifield-value-decl (non-derived-ifields (current-ifld-list))) "};\n\n" ) @@ -237,7 +241,7 @@ ; ??? It might be useful to define the handler in Scheme. Later. (define opc-parse-handlers '((insn-normal))) -(define opc-insert-handlers '((insn-normal))) +(define opc-insert-handlers '((insn-normal) (insn-macro-string))) (define opc-extract-handlers '((insn-normal))) (define opc-print-handlers '((insn-normal))) @@ -337,7 +341,7 @@ " " (gen-insn-handlers insn) ",\n" " " (gen-syntax-entry "MNEM" "OP" (insn-syntax insn)) ",\n" ; ??? 'twould save space to put a pointer here and record format separately - " " (gen-ifmt-entry insn) ", " + " { " (gen-ifmt-entry insn) " }, " ;"0x" (number->string (insn-value insn) 16) ",\n" (gen-ivalue-entry insn) "\n" " },\n")) @@ -363,7 +367,7 @@ static const CGEN_OPCODE @arch@_cgen_ins /* Special null first entry. A `num' value of zero is thus invalid. Also, the special `invalid' insn resides here. */ - { { 0, 0, 0, 0 }, {{0}}, 0, {0}},\n" + { { 0, 0, 0, 0 }, {{0}}, {0}, {0}},\n" (lambda () (string-write-map (lambda (insn) @@ -494,18 +498,36 @@ static unsigned int dis_hash_insn PARAMS (gen-obj-sanitize minsn (string-list - " /* " (minsn-syntax minsn) " */\n" + "/* " (minsn-syntax minsn) " */\n" " {\n" " " "-1, " ; macro-insns are not currently enumerated, no current need to "\"" (obj:name minsn) "\", " - "\"" (minsn-mnemonic minsn) "\",\n" - " " (gen-syntax-entry "MNEM" "OP" (minsn-syntax minsn)) ",\n" - " (PTR) & macro_" (gen-sym minsn) "_expansions[0],\n" + "\"" (minsn-mnemonic minsn) "\", -1,\n" " " - (gen-obj-attr-defn 'minsn minsn all-attrs num-non-bools gen-insn-attr-mask) - "\n" - " },\n")) + (gen-obj-attr-defn 'minsn minsn all-attrs num-non-bools gen-A-attr-mask) +;;; (gen-bool-attrs (obj-atlist minsn) gen-A-attr-mask) + "\n },\n")) +) + +;;; macro string expansion is a list of strings, each representing +;;; an assembler insn. Combine them into a single C string with +;;; newline separators and TAB prefixes, except that insns strings +;;; beginning with "*" don't get TAB (this is used for labels that +;;; want to begin in the first column). +(define (-gen-minsn-macro-string-expansion expans) + (cond ((null? expans) + "") + ((string? expans) + (string-append "\\\n" + (if (char=? (string-ref expans 0) #\*) + (substring expans 1 (string-length expans)) + (string-append "\t" expans)) + "\\n")) + ((and (list? expans) + (string? (car expans))) + (string-append (-gen-minsn-macro-string-expansion (car expans)) + (-gen-minsn-macro-string-expansion (cdr expans))))) ) ; Return a macro-insn opcode table entry. @@ -515,17 +537,21 @@ static unsigned int dis_hash_insn PARAMS (gen-obj-sanitize minsn (string-list - " /* " (minsn-syntax minsn) " */\n" + "/* " (minsn-syntax minsn) " */\n" " {\n" - " " - "-1, " ; macro-insns are not currently enumerated, no current need to - "\"" (obj:name minsn) "\", " - "\"" (minsn-mnemonic minsn) "\",\n" - " " (gen-syntax-entry "MNEM" "OP" (minsn-syntax minsn)) ",\n" - " (PTR) & macro_" (gen-sym minsn) "_expansions[0],\n" - " " - (gen-obj-attr-defn 'minsn minsn all-attrs num-non-bools gen-insn-attr-mask) - "\n" + " { 0, 1, 0, 0 },\n" + ;; macro-insns are not currently enumerated, no current need to + " " (gen-syntax-entry "MNEM" "OP" (minsn-syntax minsn)) ",\n { " + (cond ((multi-insn? minsn) + (string-append "& macro_" (gen-sym minsn) "_expansions[0]")) + ((has-attr? minsn 'STRING) + (string-append " \"" + (-gen-minsn-macro-string-expansion + (car (minsn-expansions minsn))) + "\"")) + (else + (logit 2 "Unknown expansion type in -gen-minsn-opcode-entry\n"))) + " }, { 0 }\n" " },\n")) ) @@ -557,16 +583,17 @@ static unsigned int dis_hash_insn PARAMS minsn-list)))) "#undef F\n\n" "/* Each non-simple macro entry points to an array of expansion possibilities. */\n\n" - (lambda () + (lambda () (string-write-map (lambda (minsn) - (if (has-attr? minsn 'ALIAS) - "" + ;; GKM FIXME: can a multi insn appear here??? + (if (multi-insn? minsn) (string-append "static const CGEN_MINSN_EXPANSION macro_" (gen-sym minsn) "_expansions[] =\n" "{\n" (string-map -gen-miexpn-entry (minsn-expansions minsn)) - " { 0, 0 }\n};\n\n"))) + " { 0, 0 }\n};\n\n") + "")) minsn-list)) (gen-define-with-symcat "A(a) (1 << CGEN_INSN_" "a)") (gen-define-with-symcat "OPERAND(op) @ARCH@_OPERAND_" "op") @@ -583,9 +610,11 @@ static const CGEN_IBASE @arch@_cgen_macr (string-write-map (lambda (minsn) (logit 3 "Generating macro-insn table entry for " (obj:name minsn) " ...\n") ; Simple macro-insns are emitted as aliases of real insns. - (if (has-attr? minsn 'ALIAS) - (gen-insn-table-entry minsn all-attrs num-non-bools) - (-gen-minsn-table-entry minsn all-attrs num-non-bools))) + (cond ((has-attr? minsn 'ALIAS) + (gen-insn-table-entry minsn all-attrs num-non-bools)) + ((has-attr? minsn 'STRING) + (-gen-minsn-table-entry minsn all-attrs num-non-bools)) + (else ""))) minsn-list)) "\ }; Index: cgen/sim-decode.scm =================================================================== RCS file: /cvs/src/src/cgen/sim-decode.scm,v retrieving revision 1.4 diff -u -p -r1.4 sim-decode.scm --- sim-decode.scm 2001/01/06 12:11:09 1.4 +++ sim-decode.scm 2001/03/02 23:25:25 @@ -433,7 +433,7 @@ void " extract_" (gen-sym sfmt) ":\n" " {\n" " const IDESC *idesc = &" IDESC-TABLE-VAR "[itype];\n" - (if (< (length (sfmt-iflds sfmt)) 0) + (if (> (length (sfmt-iflds sfmt)) 0) (string-append " CGEN_INSN_INT insn = " (if (adata-integral-insn? CURRENT-ARCH) Index: gas/read.c =================================================================== RCS file: /cvs/src/src/gas/read.c,v retrieving revision 1.32 diff -u -p -r1.32 read.c --- read.c 2000/12/28 10:07:55 1.32 +++ read.c 2001/03/02 23:25:27 @@ -219,6 +219,7 @@ static int dwarf_file_string; #endif #endif +static void maybe_print_macro_listing PARAMS ((void)); static void cons_worker PARAMS ((int, int)); static int scrub_from_string PARAMS ((char *, int)); static void do_align PARAMS ((int, char *, int, int)); @@ -638,37 +639,7 @@ read_a_source_file (name) know (c != ' '); /* No further leading whitespace. */ -#ifndef NO_LISTING - /* If listing is on, and we are expanding a macro, then give - the listing code the contents of the expanded line. */ - if (listing) - { - if ((listing & LISTING_MACEXP) && macro_nest > 0) - { - char *copy; - int len; - - /* Find the end of the current expanded macro line. */ - for (s = input_line_pointer - 1; *s; ++s) - if (is_end_of_line[(unsigned char) *s]) - break; - - /* Copy it for safe keeping. Also give an indication of - how much macro nesting is involved at this point. */ - len = s - (input_line_pointer - 1); - copy = (char *) xmalloc (len + macro_nest + 2); - memset (copy, '>', macro_nest); - copy[macro_nest] = ' '; - memcpy (copy + macro_nest + 1, input_line_pointer - 1, len); - copy[macro_nest + 1 + len] = '\0'; - - /* Install the line with the listing facility. */ - listing_newline (copy); - } - else - listing_newline (NULL); - } -#endif + maybe_print_macro_listing (); /* C is the 1st significant character. Input_line_pointer points after that character. */ if (is_name_beginner (c)) @@ -891,10 +862,29 @@ read_a_source_file (name) } } - md_assemble (s); /* Assemble 1 instruction. */ +#if MD_ASSEMBLE_MACRO + { + /* Assemble 1 instruction, or if a macro-insn, + expand it and return the expansion. */ + const char *expand_str = md_assemble (s); + *input_line_pointer++ = c; + if (expand_str) + { + sb expand_sb; + sb_new (&expand_sb); + sb_add_string (&expand_sb, expand_str); + free (expand_str); + input_scrub_include_sb (&expand_sb, input_line_pointer, 1); + sb_kill (&expand_sb); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); + maybe_print_macro_listing (); + } + } +#else + md_assemble (s); /* Assemble 1 instruction. */ *input_line_pointer++ = c; - +#endif /* We resume loop AFTER the end-of-line from this instruction. */ } @@ -1091,6 +1081,44 @@ read_a_source_file (name) } #endif } + +static void +maybe_print_macro_listing () +{ +#ifndef NO_LISTING + /* If listing is on, and we are expanding a macro, then give + the listing code the contents of the expanded line. */ + if (listing) + { + if ((listing & LISTING_MACEXP) && macro_nest > 0) + { + char *copy; + int len; + char *s; + + /* Find the end of the current expanded macro line. */ + for (s = input_line_pointer - 1; *s; ++s) + if (is_end_of_line[(unsigned char) *s]) + break; + + /* Copy it for safe keeping. Also give an indication of + how much macro nesting is involved at this point. */ + len = s - (input_line_pointer - 1); + copy = (char *) xmalloc (len + macro_nest + 2); + memset (copy, '>', macro_nest); + copy[macro_nest] = ' '; + memcpy (copy + macro_nest + 1, input_line_pointer - 1, len); + copy[macro_nest + 1 + len] = '\0'; + + /* Install the line with the listing facility. */ + listing_newline (copy); + } + else + listing_newline (NULL); + } +#endif +} + /* For most MRI pseudo-ops, the line actually ends at the first nonquoted space. This function looks for that point, stuffs a null Index: gas/tc.h =================================================================== RCS file: /cvs/src/src/gas/tc.h,v retrieving revision 1.2 diff -u -p -r1.2 tc.h --- tc.h 2000/09/12 20:57:14 1.2 +++ tc.h 2001/03/02 23:25:28 @@ -1,6 +1,6 @@ /* tc.h - target cpu dependent - Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + Copyright (C) 1987, 1990, 1991, 1992, 2001 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -52,7 +52,11 @@ int md_parse_option PARAMS ((int c, char void md_show_usage PARAMS ((FILE *)); long md_pcrel_from PARAMS ((fixS * fixP)); short tc_coff_fix2rtype PARAMS ((fixS * fixP)); +#if MD_ASSEMBLE_MACRO +const char *md_assemble PARAMS ((char *str)); +#else void md_assemble PARAMS ((char *str)); +#endif void md_begin PARAMS ((void)); #ifndef md_create_long_jump void md_create_long_jump PARAMS ((char *ptr, addressT from_addr, Index: include/opcode/cgen.h =================================================================== RCS file: /cvs/src/src/include/opcode/cgen.h,v retrieving revision 1.9 diff -u -p -r1.9 cgen.h --- cgen.h 2001/02/02 23:04:39 1.9 +++ cgen.h 2001/03/02 23:25:28 @@ -904,13 +904,19 @@ typedef struct #define CGEN_OPCODE_SYNTAX(opc) (& (opc)->syntax) /* Format entry. */ - const CGEN_IFMT *format; -#define CGEN_OPCODE_FORMAT(opc) ((opc)->format) + union { + /* hard insn. */ + const CGEN_IFMT *format; +#define CGEN_OPCODE_FORMAT(opc) ((opc)->u.format) #define CGEN_OPCODE_MASK_BITSIZE(opc) CGEN_IFMT_MASK_LENGTH (CGEN_OPCODE_FORMAT (opc)) #define CGEN_OPCODE_BITSIZE(opc) CGEN_IFMT_LENGTH (CGEN_OPCODE_FORMAT (opc)) #define CGEN_OPCODE_IFLDS(opc) CGEN_IFMT_IFLDS (CGEN_OPCODE_FORMAT (opc)) + /* 1:n macro insn. */ + const char *string; +#define CGEN_OPCODE_MACRO_STRING(opc) ((opc)->u.string) + } u; - /* Instruction opcode value. */ + /* Instruction opcode value for hard insn. */ CGEN_IVALUE value; #define CGEN_OPCODE_VALUE(opc) (& (opc)->value) #define CGEN_OPCODE_BASE_VALUE(opc) (CGEN_OPCODE_VALUE (opc)->base_value) @@ -1054,6 +1060,10 @@ extern int cgen_macro_insn_count PARAMS /* Return value of base part of INSN. */ #define CGEN_INSN_BASE_VALUE(insn) \ CGEN_OPCODE_BASE_VALUE (CGEN_INSN_OPCODE (insn)) + +/* Return macro string expansion of INSN. */ +#define CGEN_INSN_MACRO_STRING(insn) \ + CGEN_OPCODE_MACRO_STRING (CGEN_INSN_OPCODE (insn)) /* Standard way to test whether INSN is supported by MACH. MACH is one of enum mach_attr. Index: opcodes/cgen-asm.c =================================================================== RCS file: /cvs/src/src/opcodes/cgen-asm.c,v retrieving revision 1.2 diff -u -p -r1.2 cgen-asm.c --- cgen-asm.c 2000/07/26 22:45:49 1.2 +++ cgen-asm.c 2001/03/02 23:25:28 @@ -1,6 +1,6 @@ /* CGEN generic assembler support code. - Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1998, 2001 Free Software Foundation, Inc. This file is part of the GNU Binutils and GDB, the GNU debugger. @@ -139,6 +139,13 @@ build_asm_hash_table (cd) asm_hash_table_entries = hash_entry_buf = (CGEN_INSN_LIST *) xmalloc (count * sizeof (CGEN_INSN_LIST)); + /* Add compiled in macro-insns. */ + + hash_entry_buf = hash_insn_array (cd, macro_insn_table->init_entries, + macro_insn_table->num_init_entries, + macro_insn_table->entry_size, + asm_hash_table, hash_entry_buf); + /* Add compiled in insns. Don't include the first one as it is a reserved entry. */ /* ??? It was the end of all hash chains, and also the special @@ -150,23 +157,16 @@ build_asm_hash_table (cd) insn_table->entry_size, asm_hash_table, hash_entry_buf); - /* Add compiled in macro-insns. */ + /* Add runtime added macro-insns. */ - hash_entry_buf = hash_insn_array (cd, macro_insn_table->init_entries, - macro_insn_table->num_init_entries, - macro_insn_table->entry_size, - asm_hash_table, hash_entry_buf); + hash_insn_list (cd, macro_insn_table->new_entries, + asm_hash_table, hash_entry_buf); /* Add runtime added insns. Later added insns will be prefered over earlier ones. */ hash_entry_buf = hash_insn_list (cd, insn_table->new_entries, asm_hash_table, hash_entry_buf); - - /* Add runtime added macro-insns. */ - - hash_insn_list (cd, macro_insn_table->new_entries, - asm_hash_table, hash_entry_buf); cd->asm_hash_table = asm_hash_table; cd->asm_hash_table_entries = asm_hash_table_entries; Index: opcodes/cgen-asm.in =================================================================== RCS file: /cvs/src/src/opcodes/cgen-asm.in,v retrieving revision 1.4 diff -u -p -r1.4 cgen-asm.in --- cgen-asm.in 2001/01/09 17:00:21 1.4 +++ cgen-asm.in 2001/03/02 23:25:29 @@ -70,6 +70,8 @@ parse_insn_normal (cd, insn, strp, field const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); const char *str = *strp; const char *errmsg; + const char **op_starts = fields->op_starts; + int *op_lengths = fields->op_lengths; const char *p; const CGEN_SYNTAX_CHAR_TYPE * syn; #ifdef CGEN_MNEMONIC_OPERANDS @@ -149,14 +151,19 @@ parse_insn_normal (cd, insn, strp, field } /* We have an operand of some sort. */ + *op_starts = str; errmsg = @arch@_cgen_parse_operand (cd, CGEN_SYNTAX_FIELD (*syn), &str, fields); + *op_lengths++ = (str - *op_starts++); if (errmsg) return errmsg; /* Done with this operand, continue with next one. */ ++ syn; } + + *op_starts = NULL; + *op_lengths = 0; /* If we're at the end of the syntax string, we're done. */ if (* syn == 0) Index: opcodes/cgen-ibld.in =================================================================== RCS file: /cvs/src/src/opcodes/cgen-ibld.in,v retrieving revision 1.4 diff -u -p -r1.4 cgen-ibld.in --- cgen-ibld.in 2001/01/09 17:00:21 1.4 +++ cgen-ibld.in 2001/03/02 23:25:29 @@ -34,6 +34,7 @@ along with this program; if not, write t #include "@prefix@-desc.h" #include "@prefix@-opc.h" #include "opintl.h" +#include "libiberty.h" #undef min #define min(a,b) ((a) < (b) ? (a) : (b)) @@ -49,6 +50,9 @@ static const char * insert_normal static const char * insert_insn_normal PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma)); +static const char * insert_insn_macro_string + PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, + CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma)); static int extract_normal PARAMS ((CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT, @@ -255,6 +259,86 @@ insert_insn_normal (cd, insn, fields, bu fields, buffer, pc); if (errmsg) return errmsg; + } + + return NULL; +} + +/* Builder for string-expansion insn macros. + The result is an error message or NULL if success. */ + +static const char * +insert_insn_macro_string (cd, insn, fields, buffer, pc) + CGEN_CPU_DESC cd; + const CGEN_INSN * insn; + CGEN_FIELDS * fields; + CGEN_INSN_BYTES_PTR buffer; + bfd_vma pc; +{ + const char *template = CGEN_INSN_MACRO_STRING (insn); + const char **op_starts = fields->op_starts; + int *op_lengths = fields->op_lengths; + char *expansion; + int length = 0; + const char *errmsg; + + /* Use normal insertion in order to check operand constraints. */ + errmsg = insert_insn_normal (cd, insn, fields, buffer, pc); + if (errmsg) + return errmsg; + + for (;;) + { + char *insertion = strchr (template, '%'); + if (insertion) + { + int ic = insertion[1]; + length += insertion++ - template; + if (ic == '%') + length++; + else if (isdigit (ic)) + length += op_lengths[ic - '0']; + else + return _("invalid positional parameter in macro string expansion"); + template = ++insertion; + } + else + { + length += strlen (template); + break; + } + } + + fields->macro_string_expansion = expansion = xmalloc (length + 1); + template = CGEN_INSN_MACRO_STRING (insn); + for (;;) + { + char *insertion = strchr (template, '%'); + if (insertion) + { + int ic = insertion[1]; + int length = insertion++ - template; + + memcpy (expansion, template, length); + expansion += length; + template += length; + if (ic == '%') + *expansion++ = '%'; + else if (isdigit (ic)) + { + ic -= '0'; + memcpy (expansion, op_starts[ic], op_lengths[ic]); + expansion += op_lengths[ic]; + } + else + return _("invalid positional parameter in macro string expansion"); + template = ++insertion; + } + else + { + strcpy (expansion, template); + break; + } } return NULL;