; Macro instruction definitions. ; Copyright (C) 2000, 2009 Red Hat, Inc. ; This file is part of CGEN. ; See file COPYING.CGEN for details. ; Expansion: ; If the macro expands to a string, arguments in the input string ; are refered to with %N. Multiple insns are separated with '\n'. ; String expansion is a special case of the normal form which is a Scheme ; expression that controls the expansion. The Scheme expression will be able ; to refer to the current assembly state to decide how to perform the ; expansion. Special expression `emit' is used to call the assembler emitter ; for a particular insn. Special expression `expand' is used to return a ; string to be reparsed (which is special cased). ; Parse a list of macro-instruction expansion descriptions. ; This is the main routine for building an minsn-expansion object from a ; 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. ; Object to describe a macro-insn. (define (class-make ' '() '( ; syntax of the macro syntax ; list of expansion expressions expansions ) nil) ) (method-make-make! '(location name comment attrs syntax expansions)) ; Accessor fns (define minsn-syntax (elm-make-getter 'syntax)) (define minsn-expansions (elm-make-getter 'expansions)) ; Return a list of the machs that support MINSN. (define (minsn-machs minsn) nil ) ; Return macro-instruction mnemonic. ; This is computed from the syntax string. (define minsn-mnemonic insn-mnemonic) ; Return enum cgen_minsn_types value for MINSN. (define (minsn-enum minsn) (string-upcase (string-append "@ARCH@_MINSN_" (gen-sym minsn))) ) ; Parse a macro-insn expansion description. ; ??? At present we only support unconditional simple expansion. (define (/minsn-parse-expansion context expn) (if (not (form? expn)) (parse-error context "invalid macro expansion" expn)) (if (not (eq? 'emit (car expn))) (parse-error context "invalid macro expansion, must be `(emit ...)'" expn)) expn ) ; Parse a macro-instruction description. ; This is the main routine for building a macro-insn object from a ; description in the .cpu file. ; All arguments are in raw (non-evaluated) form. ; The result is the parsed object or #f if object isn't for selected mach(s). (define (/minsn-parse context name comment attrs syntax expansions) (logit 2 "Processing macro-insn " name " ...\n") (if (not (list? expansions)) (parse-error context "invalid macro expansion list" expansions)) ;; Pick out name first to augment the error context. (let* ((name (parse-name context name)) (context (context-append-name context name)) (atlist-obj (atlist-parse context attrs "cgen_minsn"))) (if (keep-atlist? atlist-obj #f) (let ((result (make (context-location context) name (parse-comment context comment) atlist-obj (parse-syntax context syntax) (map (lambda (e) (/minsn-parse-expansion context e)) expansions)))) result) (begin (logit 2 "Ignoring " name ".\n") #f))) ) ; Read a macro-insn description ; This is the main routine for analyzing macro-insns in the .cpu file. ; CONTEXT is a object for error messages. ; ARG-LIST is an associative list of field name and field value. ; /minsn-parse is invoked to create the `macro-insn' object. (define (/minsn-read context . arg-list) (let ( (name nil) (comment "") (attrs nil) (syntax "") (expansions nil) ) ; Loop over each element in ARG-LIST, recording what's found. (let loop ((arg-list arg-list)) (if (null? arg-list) nil (let ((arg (car arg-list)) (elm-name (caar arg-list))) (case elm-name ((name) (set! name (cadr arg))) ((comment) (set! comment (cadr arg))) ((attrs) (set! attrs (cdr arg))) ((syntax) (set! syntax (cadr arg))) ((expansions) (set! expansions (cdr arg))) (else (parse-error context "invalid macro-insn arg" arg))) (loop (cdr arg-list))))) ; Now that we've identified the elements, build the object. (/minsn-parse context name comment attrs syntax expansions)) ) ; Define a macro-insn object, name/value pair list version. (define define-minsn (lambda arg-list (if (eq? APPLICATION 'SIMULATOR) #f ; don't waste time if simulator (let ((m (apply /minsn-read (cons (make-current-context "define-minsn") arg-list)))) (if m (current-minsn-add! m)) m))) ) ; Define a macro-insn object, all arguments specified. ; This only supports one expansion. ; Use define-minsn for the general case (??? which is of course not implemented ; yet :-). (define (define-full-minsn name comment attrs syntax expansion) (if (eq? APPLICATION 'SIMULATOR) #f ; don't waste time if simulator (let ((m (/minsn-parse (make-current-context "define-full-minsn") name comment (cons 'ALIAS attrs) syntax (list expansion)))) (if m (current-minsn-add! m)) m)) ) ; Compute the ifield list for an alias macro-insn. ; This involves making a copy of REAL-INSN's ifield list and assigning ; known quantities to operands that have fixed values in the macro-insn. (define (/minsn-compute-iflds context minsn-iflds real-insn) (let* ((iflds (list-copy (insn-iflds real-insn))) ; List of "free variables", i.e. operands. (ifld-ops (find ifld-operand? iflds)) ; Names of fields in `ifld-ops'. As elements of minsn-iflds are ; parsed the associated element in ifld-names is deleted. At the ; end ifld-names must be empty. delq! can't delete the first ; element in a list, so we insert a fencepost. (ifld-names (cons #f (map obj:name ifld-ops))) (isa-name-list (obj-isa-list real-insn))) ;(logit 3 "Computing ifld list, operand field names: " ifld-names "\n") ; For each macro-insn ifield expression, look it up in the real insn's ; ifield list. If an operand without a prespecified value, leave ; unchanged. If an operand or ifield with a value, assign the value to ; the ifield entry. (for-each (lambda (f) (let* ((op-name (if (pair? f) (car f) f)) (op-obj (current-op-lookup op-name isa-name-list)) ; If `op-name' is an operand, use its ifield. ; Otherwise `op-name' must be an ifield name. (f-name (if op-obj (obj:name (hw-index:value (op:index op-obj))) op-name)) (ifld-pair (object-memq f-name iflds))) ;(logit 3 "Processing ifield " f-name " ...\n") (if (not ifld-pair) (parse-error context "unknown operand" f)) ; Ensure `f' is an operand. (if (not (memq f-name ifld-names)) (parse-error context "not an operand" f)) (if (pair? f) (set-car! ifld-pair (ifld-new-value (car ifld-pair) (cadr f)))) (delq! f-name ifld-names))) minsn-iflds) (if (not (equal? ifld-names '(#f))) (parse-error context "incomplete operand list, missing: " (cdr ifld-names))) iflds) ) ; Create an aliased real insn from an alias macro-insn. (define (minsn-make-alias context minsn) (if (or (not (has-attr? minsn 'ALIAS)) ; Must emit exactly one real insn. (not (eq? 'emit (caar (minsn-expansions minsn))))) (parse-error context "not an alias macro-insn" minsn)) (let* ((expn (car (minsn-expansions minsn))) (alias-of (current-insn-lookup (cadr expn) (obj-isa-list minsn)))) (if (not alias-of) (parse-error context "unknown real insn in expansion" minsn)) (let ((i (make (context-location context) (obj:name minsn) (obj:comment minsn) (obj-atlist minsn) (minsn-syntax minsn) (/minsn-compute-iflds (context-append context (string-append ": " (obj:str-name minsn))) (cddr expn) alias-of) #f ; ifield-assertion #f ; semantics #f ; timing ))) ; FIXME: use same format entry as real insn, ; build mask and test value at run time. (insn-set-ifmt! i (ifmt-build i -1 #f (insn-iflds i))) ; (car (ifmt-analyze i #f)))) ;(insn-set-ifmt! i (insn-ifmt alias-of)) i)) ) ; Called before a .cpu file is read in. (define (minsn-init!) (reader-add-command! 'define-minsn "\ Define a macro instruction, name/value pair list version. " nil 'arg-list define-minsn) (reader-add-command! 'define-full-minsn "\ Define a macro instruction, all arguments specified. " nil '(name comment attrs syntax expansion) define-full-minsn) *UNSPECIFIED* ) ; Called after the .cpu file has been read in. (define (minsn-finish!) *UNSPECIFIED* )