summaryrefslogtreecommitdiff
path: root/cgen/rtl.scm
diff options
context:
space:
mode:
Diffstat (limited to 'cgen/rtl.scm')
-rw-r--r--cgen/rtl.scm2205
1 files changed, 2205 insertions, 0 deletions
diff --git a/cgen/rtl.scm b/cgen/rtl.scm
new file mode 100644
index 00000000000..c6c55b40bd3
--- /dev/null
+++ b/cgen/rtl.scm
@@ -0,0 +1,2205 @@
+; Basic RTL support.
+; Copyright (C) 2000 Red Hat, Inc.
+; This file is part of CGEN.
+; See file COPYING.CGEN for details.
+
+; The name for the description language has been changed a couple of times.
+; RTL isn't my favorite because of perceived confusion with GCC
+; (and perceived misinterpretation of intentions!).
+; On the other hand my other choices were taken (and believed to be
+; more confusing).
+;
+; RTL functions are described by class <rtx-func>.
+; The complete list of rtl functions is defined in doc/rtl.texi.
+
+; Conventions used in this file:
+; - procs that perform the basic rtl or semantic expression manipulation that
+; is for public use shall be prefixed with "s-" or "rtl-" or "rtx-"
+; - no other procs shall be so prefixed
+; - rtl globals and other rtx-func object support shall be prefixed with
+; "-rtx[-:]"
+; - no other procs shall be so prefixed
+
+; Class for defining rtx nodes.
+
+; FIXME: Add new members that are lambda's to perform the argument checking
+; specified by `arg-types' and `arg-modes'. This will save a lookup during
+; traversing. It will also allow custom versions for oddballs (e.g. for
+; `member' we want to verify the 2nd arg is a `number-list' rtx).
+; ??? Still useful?
+
+(define <rtx-func>
+ (class-make '<rtx-func> nil
+ '(
+ ; name as it appears in RTL
+ name
+
+ ; argument list
+ args
+
+ ; types of each argument, as symbols
+ ; This is #f for macros.
+ ; Possible values:
+ ; OPTIONS - optional list of :-prefixed options.
+ ; ANYMODE - any mode
+ ; INTMODE - any integer mode
+ ; FLOATMODE - any floating point mode
+ ; NUMMODE - any numeric mode
+ ; EXPLNUMMODE - explicit numeric mode, can't be DFLT or VOID
+ ; NONVOIDMODE - can't be `VOID'
+ ; VOIDMODE - must be `VOID'
+ ; DFLTMODE - must be `DFLT', used when any mode is inappropriate
+ ; RTX - any rtx
+ ; SETRTX - any rtx allowed to be `set'
+ ; TESTRTX - the test of an `if'
+ ; CONDRTX - a cond expression ((test) rtx ... rtx)
+ ; CASERTX - a case expression ((symbol .. symbol) rtx ... rtx)
+ ; LOCALS - the locals list of a sequence
+ ; ENV - environment stack
+ ; ATTRS - attribute list
+ ; SYMBOL - operand must be a symbol
+ ; STRING - operand must be a string
+ ; NUMBER - operand must be a number
+ ; SYMORNUM - operand must be a symbol or number
+ ; OBJECT - operand is an object
+ arg-types
+
+ ; required mode of each argument
+ ; This is #f for macros.
+ ; Possible values include any mode name and:
+ ; ANY - any mode
+ ; NA - not applicable
+ ; OP0 - mode is specified in operand 0
+ ; unless it is DFLT in which case use the default mode
+ ; of the operand
+ ; MATCH1 - must match mode of operand 1
+ ; which will have OP0 for its mode spec
+ ; MATCH2 - must match mode of operand 2
+ ; which will have OP0 for its mode spec
+ ; <MODE-NAME> - must match specified mode
+ arg-modes
+
+ ; The class of rtx.
+ ; This is #f for macros.
+ ; ARG - operand, local, const
+ ; SET - set
+ ; UNARY - not, inv, etc.
+ ; BINARY - add, sub, etc.
+ ; TRINARY - addc, subc, etc.
+ ; IF - if
+ ; COND - cond, case
+ ; SEQUENCE - sequence, parallel
+ ; UNSPEC - c-call
+ ; MISC - everything else
+ class
+
+ ; A symbol indicating the flavour of rtx node this is.
+ ; function - normal function
+ ; syntax - don't pre-eval arguments
+ ; operand - result is an operand
+ ; macro - converts one rtx expression to another
+ ; The word "style" was chosen to be sufficiently different
+ ; from "type", "kind", and "class".
+ style
+
+ ; A function to perform the rtx.
+ evaluator
+
+ ; Ordinal number of rtx. Used to index into tables.
+ num
+ )
+ nil)
+)
+
+; Predicate.
+
+(define (rtx-func? x) (class-instance? <rtx-func> x))
+
+; Accessor fns
+
+(define-getters <rtx-func> rtx
+ (name args arg-types arg-modes class style evaluator num)
+)
+
+(define (rtx-class-arg? rtx) (eq? (rtx-class rtx) 'ARG))
+(define (rtx-class-set? rtx) (eq? (rtx-class rtx) 'SET))
+(define (rtx-class-unary? rtx) (eq? (rtx-class rtx) 'UNARY))
+(define (rtx-class-binary? rtx) (eq? (rtx-class rtx) 'BINARY))
+(define (rtx-class-trinary? rtx) (eq? (rtx-class rtx) 'TRINARY))
+(define (rtx-class-if? rtx) (eq? (rtx-class rtx) 'IF))
+(define (rtx-class-cond? rtx) (eq? (rtx-class rtx) 'COND))
+(define (rtx-class-sequence? rtx) (eq? (rtx-class rtx) 'SEQUENCE))
+(define (rtx-class-unspec? rtx) (eq? (rtx-class rtx) 'UNSPEC))
+(define (rtx-class-misc? rtx) (eq? (rtx-class rtx) 'MISC))
+
+(define (rtx-style-function? rtx) (eq? (rtx-style rtx) 'function))
+(define (rtx-style-syntax? rtx) (eq? (rtx-style rtx) 'syntax))
+(define (rtx-style-operand? rtx) (eq? (rtx-style rtx) 'operand))
+(define (rtx-style-macro? rtx) (eq? (rtx-style rtx) 'macro))
+
+; Add standard `get-name' method since this isn't a subclass of <ident>.
+
+(method-make! <rtx-func> 'get-name (lambda (self) (elm-get self 'name)))
+
+; List of valid values for arg-types, not including mode names.
+
+(define -rtx-valid-types
+ '(OPTIONS
+ ANYMODE INTMODE FLOATMODE NUMMODE EXPLNUMMODE NONVOIDMODE VOIDMODE DFLTMODE
+ RTX TESTRTX CONDRTX CASERTX
+ LOCALS ENV ATTRS SYMBOL STRING NUMBER SYMORNUM OBJECT)
+)
+
+; List of valid mode matchers, excluding mode names.
+
+(define -rtx-valid-matches
+ '(ANY NA OP0 MATCH1 MATCH2)
+)
+
+; List of all defined rtx names. This can be map'd over without having
+; to know the innards of -rtx-func-table (which is a hash table).
+
+(define -rtx-name-list nil)
+(define (rtx-name-list) -rtx-name-list)
+
+; Table of rtx function objects.
+; This is set in rtl-init!.
+
+(define -rtx-func-table nil)
+
+; Look up the <rtx-func> object for RTX-KIND.
+; Returns the object or #f if not found.
+; RTX-KIND may already be an <rtx-func> object. FIXME: delete?
+
+(define (rtx-lookup rtx-kind)
+ (cond ((symbol? rtx-kind)
+ (hashq-ref -rtx-func-table rtx-kind))
+ ((rtx-func? rtx-kind)
+ rtx-kind)
+ (else #f))
+)
+
+; Table of rtx macro objects.
+; This is set in rtl-init!.
+
+(define -rtx-macro-table nil)
+
+; Table of operands, modes, and other non-functional aspects of RTL.
+; This is defined in rtl-finish!, after all operands have been read in.
+
+(define -rtx-operand-table nil)
+
+; Number of next rtx to be defined.
+
+(define -rtx-num-next #f)
+
+; Return the number of rtx's.
+
+(define (rtx-max-num)
+ -rtx-num-next
+)
+
+; Define Rtx Node
+;
+; Add an entry to the rtx function table.
+; NAME-ARGS is a list of the operation name and arguments.
+; The mode of the result must be the first element in `args' (if there are
+; any arguments).
+; ARG-TYPES is a list of argument types (-rtx-valid-types).
+; ARG-MODES is a list of mode matchers (-rtx-valid-matches).
+; ACTION is a list of Scheme expressions to perform the operation.
+;
+; ??? Note that we can support variables. Not sure it should be done.
+
+(define (def-rtx-node name-args arg-types arg-modes class action)
+ (let ((name (car name-args))
+ (args (cdr name-args)))
+ (let ((rtx (make <rtx-func> name args
+ arg-types arg-modes
+ class
+ 'function
+ (if action
+ (eval (list 'lambda (cons '*estate* args) action))
+ #f)
+ -rtx-num-next)))
+ ; Add it to the table of rtx handlers.
+ (hashq-set! -rtx-func-table name rtx)
+ (set! -rtx-num-next (+ -rtx-num-next 1))
+ (set! -rtx-name-list (cons name -rtx-name-list))
+ *UNSPECIFIED*))
+)
+
+(define define-rtx-node
+ ; Written this way so Hobbit can handle it.
+ (defmacro:syntax-transformer (lambda arg-list
+ (apply def-rtx-node arg-list)
+ nil))
+)
+
+; Same as define-rtx-node but don't pre-evaluate the arguments.
+; Remember that `mode' must be the first argument.
+
+(define (def-rtx-syntax-node name-args arg-types arg-modes class action)
+ (let ((name (car name-args))
+ (args (cdr name-args)))
+ (let ((rtx (make <rtx-func> name args
+ arg-types arg-modes
+ class
+ 'syntax
+ (if action
+ (eval (list 'lambda (cons '*estate* args) action))
+ #f)
+ -rtx-num-next)))
+ ; Add it to the table of rtx handlers.
+ (hashq-set! -rtx-func-table name rtx)
+ (set! -rtx-num-next (+ -rtx-num-next 1))
+ (set! -rtx-name-list (cons name -rtx-name-list))
+ *UNSPECIFIED*))
+)
+
+(define define-rtx-syntax-node
+ ; Written this way so Hobbit can handle it.
+ (defmacro:syntax-transformer (lambda arg-list
+ (apply def-rtx-syntax-node arg-list)
+ nil))
+)
+
+; Same as define-rtx-node but return an operand (usually an <operand> object).
+; ??? `mode' must be the first argument?
+
+(define (def-rtx-operand-node name-args arg-types arg-modes class action)
+ ; Operand nodes must specify an action.
+ (assert action)
+ (let ((name (car name-args))
+ (args (cdr name-args)))
+ (let ((rtx (make <rtx-func> name args
+ arg-types arg-modes
+ class
+ 'operand
+ (eval (list 'lambda (cons '*estate* args) action))
+ -rtx-num-next)))
+ ; Add it to the table of rtx handlers.
+ (hashq-set! -rtx-func-table name rtx)
+ (set! -rtx-num-next (+ -rtx-num-next 1))
+ (set! -rtx-name-list (cons name -rtx-name-list))
+ *UNSPECIFIED*))
+)
+
+(define define-rtx-operand-node
+ ; Written this way so Hobbit can handle it.
+ (defmacro:syntax-transformer (lambda arg-list
+ (apply def-rtx-operand-node arg-list)
+ nil))
+)
+
+; Convert one rtx expression into another.
+; NAME-ARGS is a list of the operation name and arguments.
+; ACTION is a list of Scheme expressions to perform the operation.
+; The result of ACTION must be another rtx expression (a list).
+
+(define (def-rtx-macro-node name-args action)
+ ; macro nodes must specify an action
+ (assert action)
+ (let ((name (car name-args))
+ (args (cdr name-args)))
+ (let ((rtx (make <rtx-func> name args #f #f
+ #f ; class
+ 'macro
+ (eval (list 'lambda args action))
+ -rtx-num-next)))
+ ; Add it to the table of rtx macros.
+ (hashq-set! -rtx-macro-table name rtx)
+ (set! -rtx-num-next (+ -rtx-num-next 1))
+ (set! -rtx-name-list (cons name -rtx-name-list))
+ *UNSPECIFIED*))
+)
+
+(define define-rtx-macro-node
+ ; Written this way so Hobbit can handle it.
+ (defmacro:syntax-transformer (lambda arg-list
+ (apply def-rtx-macro-node arg-list)
+ nil))
+)
+
+; RTL macro expansion.
+; RTL macros are different than pmacros. The difference is that the expansion
+; happens internally, RTL macros are part of the language.
+
+; Lookup MACRO-NAME and return its <rtx-func> object or #f if not found.
+
+(define (-rtx-macro-lookup macro-name)
+ (hashq-ref -rtx-macro-table macro-name)
+)
+
+; Lookup (car exp) and return the macro's lambda if it is one or #f.
+
+(define (-rtx-macro-check exp fn-getter)
+ (let ((macro (hashq-ref -rtx-macro-table (car exp))))
+ (if macro
+ (fn-getter macro)
+ #f))
+)
+
+; Expand a list.
+
+(define (-rtx-macro-expand-list exp fn-getter)
+ (let ((macro (-rtx-macro-check exp fn-getter)))
+ (if macro
+ (apply macro (map (lambda (x) (-rtx-macro-expand x fn-getter))
+ (cdr exp)))
+ (map (lambda (x) (-rtx-macro-expand x fn-getter))
+ exp)))
+)
+
+; Main entry point to expand a macro invocation.
+
+(define (-rtx-macro-expand exp fn-getter)
+ (if (pair? exp) ; pair? -> cheap (and (not (null? exp)) (list? exp))
+ (let ((result (-rtx-macro-expand-list exp fn-getter)))
+ ; If the result is a new macro invocation, recurse.
+ (if (pair? result)
+ (let ((macro (-rtx-macro-check result fn-getter)))
+ (if macro
+ (-rtx-macro-expand (apply macro (cdr result)) fn-getter)
+ result))
+ result))
+ exp)
+)
+
+; Publically accessible version.
+
+(define rtx-macro-expand -rtx-macro-expand)
+
+; RTX canonicalization.
+; ??? wip
+
+; Subroutine of rtx-canonicalize.
+; Return canonical form of rtx expression EXPR.
+; CONTEXT is a <context> object or #f if there is none.
+; It is used for error message.
+; RTX-OBJ is the <rtx-func> object of (car expr).
+
+(define (-rtx-canonicalize-expr context rtx-obj expr)
+ #f
+)
+
+; Return canonical form of EXPR.
+; CONTEXT is a <context> object or #f if there is none.
+; It is used for error message.
+;
+; Does:
+; - operand shortcuts expanded
+; - numbers -> (const number)
+; - operand-name -> (operand operand-name)
+; - ifield-name -> (ifield ifield-name)
+; - no options -> null option list
+; - absent result mode of those that require a mode -> DFLT
+; - rtx macros are expanded
+;
+; EXPR is returned in source form. We could speed up future processing by
+; transforming it into a more compiled form, but that makes debugging more
+; difficult, so for now we don't.
+
+(define (rtx-canonicalize context expr)
+ ; FIXME: wip
+ (cond ((integer? expr)
+ (rtx-make-const 'INT expr))
+ ((symbol? expr)
+ (let ((op (current-op-lookup expr)))
+ (if op
+ (rtx-make-operand expr)
+ (context-error context "can't canonicalize" expr))))
+ ((pair? expr)
+ expr)
+ (else
+ (context-error context "can't canonicalize" expr)))
+)
+
+; RTX mode support.
+
+; Get implied mode of X, either an operand expression, sequence temp, or
+; a hardware reference expression.
+; The result is the name of the mode.
+
+(define (rtx-lvalue-mode-name estate x)
+ (assert (rtx? x))
+ (case (car x)
+; ((operand) (obj:name (op:mode (current-op-lookup (cadr x)))))
+ ((xop) (obj:name (send (rtx-xop-obj x) 'get-mode)))
+; ((opspec)
+; (if (eq? (rtx-opspec-mode x) 'VOID)
+; (rtx-lvalue-mode-name estate (rtx-opspec-hw-ref x))
+; (rtx-opspec-mode x)))
+; ((reg mem) (cadr x))
+; ((local) (obj:name (rtx-temp-mode (rtx-temp-lookup (estate-env estate)
+; (cadr x)))))
+ (else
+ (error "rtx-lvalue-mode-name: not an operand or hardware reference:" x)))
+)
+
+; Lookup the mode to use for semantic operations (unsigned modes aren't
+; allowed since we don't have ANDUSI, etc.).
+; ??? I have actually implemented both ways (full use of unsigned modes
+; and mostly hidden use of unsigned modes). Neither makes me real
+; comfortable, though I liked bringing unsigned modes out into the open
+; even if it doubled the number of semantic operations.
+
+(define (-rtx-sem-mode m) (or (mode:sem-mode m) m))
+
+; MODE is a mode name or <mode> object.
+(define (-rtx-lazy-sem-mode mode) (-rtx-sem-mode (mode:lookup mode)))
+
+; Return the mode of object OBJ.
+
+(define (-rtx-obj-mode obj) (send obj 'get-mode))
+
+; Return a boolean indicating of modes M1,M2 are compatible.
+
+(define (-rtx-mode-compatible? m1 m2)
+ (let ((mode1 (-rtx-lazy-sem-mode m1))
+ (mode2 (-rtx-lazy-sem-mode m2)))
+ ;(eq? (obj:name mode1) (obj:name mode2)))
+ ; ??? This is more permissive than is perhaps proper.
+ (mode-compatible? 'sameclass mode1 mode2))
+)
+
+; Environments (sequences with local variables).
+
+; Temporaries are created within a sequence.
+; e.g. (sequence ((WI tmp)) (set tmp reg0) ...)
+; ??? Perhaps what we want here is `let' but for now I prefer `sequence'.
+; This isn't exactly `let' either as no initial value is specified.
+; Environments are also used to specify incoming values from the top level.
+
+(define <rtx-temp> (class-make '<rtx-temp> nil '(name mode value) nil))
+
+;(define cx-temp:name (elm-make-getter <c-expr-temp> 'name))
+;(define cx-temp:mode (elm-make-getter <c-expr-temp> 'mode))
+;(define cx-temp:value (elm-make-getter <c-expr-temp> 'value))
+
+(define-getters <rtx-temp> rtx-temp (name mode value))
+
+(method-make!
+ <rtx-temp> 'make!
+ (lambda (self name mode value)
+ (elm-set! self 'name name)
+ (elm-set! self 'mode mode)
+ (elm-set! self 'value (if value value (gen-temp name)))
+ self)
+)
+
+(define (gen-temp name)
+ ; ??? calls to gen-c-symbol don't belong here
+ (string-append "tmp_" (gen-c-symbol name))
+)
+
+; Return a boolean indicating if X is an <rtx-temp>.
+
+(define (rtx-temp? x) (class-instance? <rtx-temp> x))
+
+; Respond to 'get-mode messages.
+
+(method-make! <rtx-temp> 'get-mode (lambda (self) (elm-get self 'mode)))
+
+; Respond to 'get-name messages.
+
+(method-make! <rtx-temp> 'get-name (lambda (self) (elm-get self 'name)))
+
+; An environment is a list of <rtx-temp> objects.
+; An environment stack is a list of environments.
+
+(define (rtx-env-stack-empty? env-stack) (null? env-stack))
+(define (rtx-env-stack-head env-stack) (car env-stack))
+(define (rtx-env-var-list env) env)
+(define (rtx-env-empty-stack) nil)
+(define (rtx-env-init-stack1 vars-alist)
+ (if (null? vars-alist)
+ nil
+ (cons (rtx-env-make vars-alist) nil))
+)
+(define (rtx-env-empty? env) (null? env))
+
+; Create an initial environment.
+; VAR-LIST is a list of (name <mode> value) elements.
+
+(define (rtx-env-make var-list)
+ ; Convert VAR-LIST to an associative list of <rtx-temp> objects.
+ (map (lambda (var-spec)
+ (cons (car var-spec)
+ (make <rtx-temp>
+ (car var-spec) (cadr var-spec) (caddr var-spec))))
+ var-list)
+)
+
+; Create an initial environment with local variables.
+; VAR-LIST is a list of (mode-name name) elements (the argument to `sequence').
+
+(define (rtx-env-make-locals var-list)
+ ; Convert VAR-LIST to an associative list of <rtx-temp> objects.
+ (map (lambda (var-spec)
+ (cons (cadr var-spec)
+ (make <rtx-temp>
+ (cadr var-spec) (mode:lookup (car var-spec)) #f)))
+ var-list)
+)
+
+; Push environment ENV onto the front of environment stack ENV-STACK,
+; returning a new object. ENV-STACK is not modified.
+
+(define (rtx-env-push env-stack env)
+ (cons env env-stack)
+)
+
+(define (rtx-temp-lookup env name)
+ ;(display "looking up:") (display name) (newline)
+ (let loop ((stack (rtx-env-var-list env)))
+ (if (null? stack)
+ #f
+ (let ((temp (assq-ref (car stack) name)))
+ (if temp
+ temp
+ (loop (cdr stack))))))
+)
+
+; Create a "closure" of EXPR using the current temp stack.
+
+(define (-rtx-closure-make estate expr)
+ (rtx-make 'closure expr (estate-env estate))
+)
+
+(define (rtx-env-dump env)
+ (let ((stack env))
+ (if (rtx-env-stack-empty? stack)
+ (display "rtx-env stack (empty):\n")
+ (let loop ((stack stack) (level 0))
+ (if (null? stack)
+ #f ; done
+ (begin
+ (display "rtx-env stack, level ")
+ (display level)
+ (display ":\n")
+ (for-each (lambda (var)
+ (display " ")
+ ;(display (obj:name (rtx-temp-mode (cdr var))))
+ ;(display " ")
+ (display (rtx-temp-name (cdr var)))
+ (newline))
+ (car stack))
+ (loop (cdr stack) (+ level 1)))))))
+)
+
+; Build, test, and analyze various kinds of rtx's.
+; ??? A lot of this could be machine generated except that I don't yet need
+; that much.
+
+(define (rtx-make kind . args)
+ (cons kind (-rtx-munge-mode&options args))
+)
+
+(define rtx-name car)
+(define (rtx-kind? kind rtx) (eq? kind (rtx-name rtx)))
+
+(define (rtx-make-const mode value) (rtx-make 'const mode value))
+(define (rtx-make-enum mode value) (rtx-make 'enum mode value))
+
+(define (rtx-constant? rtx) (memq (rtx-name rtx) '(const enum)))
+
+; Return value of constant RTX (either const or enum).
+(define (rtx-constant-value rtx)
+ (case (rtx-name rtx)
+ ((const) (rtx-const-value rtx))
+ ((enum) (enum-lookup-val (rtx-enum-value rtx)))
+ (else (error "rtx-constant-value: not const or enum" rtx)))
+)
+
+(define rtx-options cadr)
+(define rtx-mode caddr)
+(define rtx-args cdddr)
+(define rtx-arg1 cadddr)
+(define (rtx-arg2 rtx) (car (cddddr rtx)))
+
+(define rtx-const-value rtx-arg1)
+(define rtx-enum-value rtx-arg1)
+
+(define rtx-reg-name rtx-arg1)
+
+; Return register number or #f if absent.
+; (reg options mode hw-name [regno [selector]])
+(define (rtx-reg-number rtx) (list-maybe-ref rtx 4))
+
+; Return register selector or #f if absent.
+(define (rtx-reg-selector rtx) (list-maybe-ref rtx 5))
+
+; Return both register number and selector.
+(define rtx-reg-index-sel cddddr)
+
+; Return memory address.
+(define rtx-mem-addr rtx-arg1)
+
+; Return memory selector or #f if absent.
+(define (rtx-mem-sel mem) (list-maybe-ref mem 4))
+
+; Return both memory address and selector.
+(define rtx-mem-index-sel cdddr)
+
+; Return MEM with new address NEW-ADDR.
+; ??? Complicate as necessary.
+(define (rtx-change-address mem new-addr)
+ (rtx-make 'mem
+ (rtx-options mem)
+ (rtx-mode mem)
+ new-addr
+ (rtx-mem-sel mem))
+)
+
+; Return argument to `symbol' rtx.
+(define rtx-symbol-name rtx-arg1)
+
+(define (rtx-make-ifield ifield-name) (rtx-make 'ifield ifield-name))
+(define (rtx-ifield? rtx) (eq? 'ifield (rtx-name rtx)))
+(define (rtx-ifield-name rtx)
+ (let ((ifield (rtx-arg1 rtx)))
+ (if (symbol? ifield)
+ ifield
+ (obj:name ifield)))
+)
+(define (rtx-ifield-obj rtx)
+ (let ((ifield (rtx-arg1 rtx)))
+ (if (symbol? ifield)
+ (current-ifield-lookup ifield)
+ ifield))
+)
+
+(define (rtx-make-operand op-name) (rtx-make 'operand op-name))
+(define (rtx-operand? rtx) (eq? 'operand (rtx-name rtx)))
+(define (rtx-operand-name rtx)
+ (let ((operand (rtx-arg1 rtx)))
+ (if (symbol? operand)
+ operand
+ (obj:name operand)))
+)
+(define (rtx-operand-obj rtx)
+ (let ((operand (rtx-arg1 rtx)))
+ (if (symbol? operand)
+ (current-op-lookup operand)
+ operand))
+)
+
+(define (rtx-make-local local-name) (rtx-make 'local local-name))
+(define (rtx-local? rtx) (eq? 'local (rtx-name rtx)))
+(define (rtx-local-name rtx)
+ (let ((local (rtx-arg1 rtx)))
+ (if (symbol? local)
+ local
+ (obj:name local)))
+)
+(define (rtx-local-obj rtx)
+ (let ((local (rtx-arg1 rtx)))
+ (if (symbol? local)
+ (error "can't use rtx-local-obj on local name")
+ local))
+)
+
+(define rtx-xop-obj rtx-arg1)
+
+;(define (rtx-opspec? rtx) (eq? 'opspec (rtx-name rtx)))
+;(define (rtx-opspec-mode rtx) (rtx-mode rtx))
+;(define (rtx-opspec-hw-ref rtx) (list-ref rtx 5))
+;(define (rtx-opspec-set-op-num! rtx num) (set-car! (cddddr rtx) num))
+
+(define rtx-index-of-value rtx-arg1)
+
+(define (rtx-make-set dest src) (rtx-make 'set dest src))
+(define rtx-set-dest rtx-arg1)
+(define rtx-set-src rtx-arg2)
+(define (rtx-single-set? rtx) (eq? (car rtx) 'set))
+
+(define rtx-alu-op-mode rtx-mode)
+(define (rtx-alu-op-arg rtx n) (list-ref rtx (+ n 3)))
+
+(define (rtx-boolif-op-arg rtx n) (list-ref rtx (+ n 3)))
+
+(define rtx-cmp-op-mode rtx-mode)
+(define (rtx-cmp-op-arg rtx n) (list-ref rtx (+ n 3)))
+
+(define rtx-number-list-values cdddr)
+
+(define rtx-member-value rtx-arg1)
+(define (rtx-member-set rtx) (list-ref rtx 4))
+
+(define rtx-if-mode rtx-mode)
+(define (rtx-if-test rtx) (rtx-arg1 rtx))
+(define (rtx-if-then rtx) (list-ref rtx 4))
+; If `else' clause is missing the result is #f.
+(define (rtx-if-else rtx) (list-maybe-ref rtx 5))
+
+(define (rtx-eq-attr-owner rtx) (list-ref rtx 3))
+(define (rtx-eq-attr-attr rtx) (list-ref rtx 4))
+(define (rtx-eq-attr-value rtx) (list-ref rtx 5))
+
+(define (rtx-sequence-locals rtx) (cadddr rtx))
+(define (rtx-sequence-exprs rtx) (cddddr rtx))
+
+; Same as rtx-sequence-locals except return in assq'able form.
+
+(define (rtx-sequence-assq-locals rtx)
+ (let ((locals (rtx-sequence-locals rtx)))
+ (map (lambda (local)
+ (list (cadr local) (car local)))
+ locals))
+)
+
+; Return a semi-pretty symbol describing RTX.
+; This is used by hw to include the index in the element's name.
+
+(define (rtx-pretty-name rtx)
+ (if (pair? rtx)
+ (case (car rtx)
+ ((const) (number->string (rtx-const-value rtx)))
+ ((operand) (obj:name (rtx-operand-obj rtx)))
+ ((local) (rtx-local-name rtx))
+ ((xop) (obj:name (rtx-xop-obj rtx)))
+ (else
+ (if (null? (cdr rtx))
+ (car rtx)
+ (apply string-append
+ (cons (car rtx)
+ (map (lambda (elm)
+ (string-append "-" (rtx-pretty-name elm)))
+ (cdr rtx)))))))
+ (stringize rtx "-"))
+)
+
+; RTL expression traversal support.
+; Traversal (and compilation) involves validating the source form and
+; converting it to internal form.
+; ??? At present the internal form is also the source form (easier debugging).
+
+; Set to #t to debug rtx traversal.
+
+(define -rtx-traverse-debug? #f)
+
+; Container to record the current state of traversal.
+; This is initialized before traversal, and modified (in a copy) as the
+; traversal state changes.
+; This doesn't record all traversal state, just the more static elements.
+; There's no point in recording things like the parent expression and operand
+; position as they change for every sub-traversal.
+; The main raison d'etre for this class is so we can add more state without
+; having to modify all the traversal handlers.
+; ??? At present it's not a proper "class" as there's no real need.
+;
+; CONTEXT is a <context> object or #f if there is none.
+; It is used for error messages.
+;
+; EXPR-FN is a dual-purpose beast. The first purpose is to just process
+; the current expression and return the result. The second purpose is to
+; lookup the function which will then process the expression.
+; It is applied recursively to the expression and each sub-expression.
+; It must be defined as
+; (lambda (rtx-obj expr mode parent-expr op-pos tstate appstuff) ...).
+; If the result of EXPR-FN is a lambda, it is applied to
+; (cons TSTATE (cdr EXPR)). TSTATE is prepended to the arguments.
+; For syntax expressions if the result of EXPR-FN is #f, the operands are
+; processed using the builtin traverser.
+; So to repeat: EXPR-FN can process the expression, and if its result is a
+; lambda then it also processes the expression. The arguments to EXPR-FN
+; are (rtx-obj expr mode parent-expr op-pos tstate appstuff). The format
+; of the result of EXPR-FN are (cons TSTATE (cdr EXPR)).
+; The reason for the duality is that when trying to understand EXPR (e.g. when
+; computing the insn format) EXPR-FN processes the expression itself, and
+; when evaluating EXPR it's the result of EXPR-FN that computes the value.
+;
+; ENV is the current environment. This is a stack of sequence locals.
+;
+; COND? is a boolean indicating if the current expression is on a conditional
+; execution path. This is for optimization purposes only and it is always ok
+; to pass #t, except for the top-level caller which must pass #f (since the top
+; level expression obviously isn't subject to any condition).
+; It is used, for example, to speed up the simulator: there's no need to keep
+; track of whether an operand has been assigned to (or potentially read from)
+; if it's known it's always assigned to.
+;
+; SET? is a boolean indicating if the current expression is an operand being
+; set.
+;
+; OWNER is the owner of the expression or #f if there is none.
+; Typically it is an <insn> object.
+;
+; KNOWN is an alist of known values. This is used by rtx-simplify.
+; Each element is (name . value) where
+; NAME is either an ifield or operand name (in the future it might be a
+; sequence local name), and
+; VALUE is either (const mode value) or (numlist mode value1 value2 ...).
+;
+; DEPTH is the current traversal depth.
+
+(define (tstate-make context owner expr-fn env cond? set? known depth)
+ (vector context owner expr-fn env cond? set? known depth)
+)
+
+(define (tstate-context state) (vector-ref state 0))
+(define (tstate-set-context! state newval) (vector-set! state 0 newval))
+(define (tstate-owner state) (vector-ref state 1))
+(define (tstate-set-owner! state newval) (vector-set! state 1 newval))
+(define (tstate-expr-fn state) (vector-ref state 2))
+(define (tstate-set-expr-fn! state newval) (vector-set! state 2 newval))
+(define (tstate-env state) (vector-ref state 3))
+(define (tstate-set-env! state newval) (vector-set! state 3 newval))
+(define (tstate-cond? state) (vector-ref state 4))
+(define (tstate-set-cond?! state newval) (vector-set! state 4 newval))
+(define (tstate-set? state) (vector-ref state 5))
+(define (tstate-set-set?! state newval) (vector-set! state 5 newval))
+(define (tstate-known state) (vector-ref state 6))
+(define (tstate-set-known! state newval) (vector-set! state 6 newval))
+(define (tstate-depth state) (vector-ref state 7))
+(define (tstate-set-depth! state newval) (vector-set! state 7 newval))
+
+; Create a copy of STATE.
+
+(define (tstate-copy state)
+ ; A fast vector-copy would be nice, but this is simple and portable.
+ (list->vector (vector->list state))
+)
+
+; Create a copy of STATE with a new environment ENV.
+
+(define (tstate-new-env state env)
+ (let ((result (tstate-copy state)))
+ (tstate-set-env! result env)
+ result)
+)
+
+; Create a copy of STATE with environment ENV pushed onto the existing
+; environment list.
+; There's no routine to pop the environment list as there's no current
+; need for it: we make a copy of the state when we push.
+
+(define (tstate-push-env state env)
+ (let ((result (tstate-copy state)))
+ (tstate-set-env! result (cons env (tstate-env result)))
+ result)
+)
+
+; Create a copy of STATE with a new COND? value.
+
+(define (tstate-new-cond? state cond?)
+ (let ((result (tstate-copy state)))
+ (tstate-set-cond?! result cond?)
+ result)
+)
+
+; Create a copy of STATE with a new SET? value.
+
+(define (tstate-new-set? state set?)
+ (let ((result (tstate-copy state)))
+ (tstate-set-set?! result set?)
+ result)
+)
+
+; Lookup NAME in the known value table. Returns the value or #f if not found.
+
+(define (tstate-known-lookup tstate name)
+ (let ((known (tstate-known tstate)))
+ (assq-ref known name))
+)
+
+; Increment the recorded traversal depth of TSTATE.
+
+(define (tstate-incr-depth! tstate)
+ (tstate-set-depth! tstate (1+ (tstate-depth tstate)))
+)
+
+; Decrement the recorded traversal depth of TSTATE.
+
+(define (tstate-decr-depth! tstate)
+ (tstate-set-depth! tstate (1- (tstate-depth tstate)))
+)
+
+; Traversal/compilation support.
+
+; Return a boolean indicating if X is a mode.
+
+(define (-rtx-any-mode? x)
+ (->bool (mode:lookup x))
+)
+
+; Return a boolean indicating if X is a symbol or rtx.
+
+(define (-rtx-symornum? x)
+ (or (symbol? x) (number? x))
+)
+
+; Traverse a list of rtx's.
+
+(define (-rtx-traverse-rtx-list rtx-list mode expr op-num tstate appstuff)
+ (map (lambda (rtx)
+ ; ??? Shouldn't OP-NUM change for each element?
+ (-rtx-traverse rtx 'RTX mode expr op-num tstate appstuff))
+ rtx-list)
+)
+
+; Cover-fn to context-error for signalling an error during rtx traversal.
+
+(define (-rtx-traverse-error tstate errmsg expr op-num)
+; (parse-error context (string-append errmsg ", operand number "
+; (number->string op-num))
+; (rtx-dump expr))
+ (context-error (tstate-context tstate)
+ (string-append errmsg ", operand #" (number->string op-num))
+ (rtx-strdump expr))
+)
+
+; Rtx traversers.
+; These are defined as individual functions that are then built into a table
+; so that we can use Hobbit's "fastcall" support.
+;
+; The result is either a pair of the parsed VAL and new TSTATE,
+; or #f meaning there is no change (saves lots of unnecessarying cons'ing).
+
+(define (-rtx-traverse-options val mode expr op-num tstate appstuff)
+ #f
+)
+
+(define (-rtx-traverse-anymode val mode expr op-num tstate appstuff)
+ (let ((val-obj (mode:lookup val)))
+ (if (not val-obj)
+ (-rtx-traverse-error tstate "expecting a mode"
+ expr op-num))
+ #f)
+)
+
+(define (-rtx-traverse-intmode val mode expr op-num tstate appstuff)
+ (let ((val-obj (mode:lookup val)))
+ (if (and val-obj
+ (or (memq (mode:class val-obj) '(INT UINT))
+ (eq? val 'DFLT)))
+ #f
+ (-rtx-traverse-error tstate "expecting an integer mode"
+ expr op-num)))
+)
+
+(define (-rtx-traverse-floatmode val mode expr op-num tstate appstuff)
+ (let ((val-obj (mode:lookup val)))
+ (if (and val-obj
+ (or (memq (mode:class val-obj) '(FLOAT))
+ (eq? val 'DFLT)))
+ #f
+ (-rtx-traverse-error tstate "expecting a float mode"
+ expr op-num)))
+)
+
+(define (-rtx-traverse-nummode val mode expr op-num tstate appstuff)
+ (let ((val-obj (mode:lookup val)))
+ (if (and val-obj
+ (or (memq (mode:class val-obj) '(INT UINT FLOAT))
+ (eq? val 'DFLT)))
+ #f
+ (-rtx-traverse-error tstate "expecting a numeric mode"
+ expr op-num)))
+)
+
+(define (-rtx-traverse-explnummode val mode expr op-num tstate appstuff)
+ (let ((val-obj (mode:lookup val)))
+ (if (not val-obj)
+ (-rtx-traverse-error tstate "expecting a mode"
+ expr op-num))
+ (if (memq val '(DFLT VOID))
+ (-rtx-traverse-error tstate "DFLT and VOID not allowed here"
+ expr op-num))
+ #f)
+)
+
+(define (-rtx-traverse-nonvoidmode val mode expr op-num tstate appstuff)
+ (if (eq? val 'VOID)
+ (-rtx-traverse-error tstate "mode can't be VOID"
+ expr op-num))
+ #f
+)
+
+(define (-rtx-traverse-voidmode val mode expr op-num tstate appstuff)
+ (if (memq val '(DFLT VOID))
+ #f
+ (-rtx-traverse-error tstate "expecting mode VOID"
+ expr op-num))
+)
+
+(define (-rtx-traverse-dfltmode val mode expr op-num tstate appstuff)
+ (if (eq? val 'DFLT)
+ #f
+ (-rtx-traverse-error tstate "expecting mode DFLT"
+ expr op-num))
+)
+
+(define (-rtx-traverse-rtx val mode expr op-num tstate appstuff)
+; Commented out 'cus it doesn't quite work yet.
+; (if (not (rtx? val))
+; (-rtx-traverse-error tstate "expecting an rtx"
+; expr op-num))
+ (cons (-rtx-traverse val 'RTX mode expr op-num tstate appstuff)
+ tstate)
+)
+
+(define (-rtx-traverse-setrtx val mode expr op-num tstate appstuff)
+ ; FIXME: Still need to turn it off for sub-exprs.
+ ; e.g. (mem (reg ...))
+; Commented out 'cus it doesn't quite work yet.
+; (if (not (rtx? val))
+; (-rtx-traverse-error tstate "expecting an rtx"
+; expr op-num))
+ (cons (-rtx-traverse val 'SETRTX mode expr op-num
+ (tstate-new-set? tstate #t)
+ appstuff)
+ tstate)
+)
+
+; This is the test of an `if'.
+
+(define (-rtx-traverse-testrtx val mode expr op-num tstate appstuff)
+; Commented out 'cus it doesn't quite work yet.
+; (if (not (rtx? val))
+; (-rtx-traverse-error tstate "expecting an rtx"
+; expr op-num))
+ (cons (-rtx-traverse val 'RTX mode expr op-num tstate appstuff)
+ (tstate-new-cond?
+ tstate
+ (not (rtx-compile-time-constant? val))))
+)
+
+(define (-rtx-traverse-condrtx val mode expr op-num tstate appstuff)
+ (if (not (pair? val))
+ (-rtx-traverse-error tstate "expecting an expression"
+ expr op-num))
+ (if (eq? (car val) 'else)
+ (begin
+ (if (!= (+ op-num 2) (length expr))
+ (-rtx-traverse-error tstate
+ "`else' clause not last"
+ expr op-num))
+ (cons (cons 'else
+ (-rtx-traverse-rtx-list
+ (cdr val) mode expr op-num
+ (tstate-new-cond? tstate #t)
+ appstuff))
+ (tstate-new-cond? tstate #t)))
+ (cons (cons
+ ; ??? Entries after the first are conditional.
+ (-rtx-traverse (car val) 'RTX 'ANY expr op-num tstate appstuff)
+ (-rtx-traverse-rtx-list
+ (cdr val) mode expr op-num
+ (tstate-new-cond? tstate #t)
+ appstuff))
+ (tstate-new-cond? tstate #t)))
+)
+
+(define (-rtx-traverse-casertx val mode expr op-num tstate appstuff)
+ (if (or (not (list? val))
+ (< (length val) 2))
+ (-rtx-traverse-error tstate
+ "invalid `case' expression"
+ expr op-num))
+ ; car is either 'else or list of symbols/numbers
+ (if (not (or (eq? (car val) 'else)
+ (and (list? (car val))
+ (not (null? (car val)))
+ (all-true? (map -rtx-symornum?
+ (car val))))))
+ (-rtx-traverse-error tstate
+ "invalid `case' choice"
+ expr op-num))
+ (if (and (eq? (car val) 'else)
+ (!= (+ op-num 2) (length expr)))
+ (-rtx-traverse-error tstate "`else' clause not last"
+ expr op-num))
+ (cons (cons (car val)
+ (-rtx-traverse-rtx-list
+ (cdr val) mode expr op-num
+ (tstate-new-cond? tstate #t)
+ appstuff))
+ (tstate-new-cond? tstate #t))
+)
+
+(define (-rtx-traverse-locals val mode expr op-num tstate appstuff)
+ (if (not (list? val))
+ (-rtx-traverse-error tstate "bad locals list"
+ expr op-num))
+ (for-each (lambda (var)
+ (if (or (not (list? var))
+ (!= (length var) 2)
+ (not (-rtx-any-mode? (car var)))
+ (not (symbol? (cadr var))))
+ (-rtx-traverse-error tstate
+ "bad locals list"
+ expr op-num)))
+ val)
+ (let ((env (rtx-env-make-locals val)))
+ (cons val (tstate-push-env tstate env)))
+)
+
+(define (-rtx-traverse-env val mode expr op-num tstate appstuff)
+ ; VAL is an environment stack.
+ (if (not (list? val))
+ (-rtx-traverse-error tstate "environment not a list"
+ expr op-num))
+ (cons val (tstate-new-env tstate val))
+)
+
+(define (-rtx-traverse-attrs val mode expr op-num tstate appstuff)
+; (cons val ; (atlist-source-form (atlist-parse val "" "with-attr"))
+; tstate)
+ #f
+)
+
+(define (-rtx-traverse-symbol val mode expr op-num tstate appstuff)
+ (if (not (symbol? val))
+ (-rtx-traverse-error tstate "expecting a symbol"
+ expr op-num))
+ #f
+)
+
+(define (-rtx-traverse-string val mode expr op-num tstate appstuff)
+ (if (not (string? val))
+ (-rtx-traverse-error tstate "expecting a string"
+ expr op-num))
+ #f
+)
+
+(define (-rtx-traverse-number val mode expr op-num tstate appstuff)
+ (if (not (number? val))
+ (-rtx-traverse-error tstate "expecting a number"
+ expr op-num))
+ #f
+)
+
+(define (-rtx-traverse-symornum val mode expr op-num tstate appstuff)
+ (if (not (or (symbol? val) (number? val)))
+ (-rtx-traverse-error tstate
+ "expecting a symbol or number"
+ expr op-num))
+ #f
+)
+
+(define (-rtx-traverse-object val mode expr op-num tstate appstuff)
+ #f
+)
+
+; Table of rtx traversers.
+; This is a vector of size rtx-max-num.
+; Each entry is a list of (arg-type-name . traverser) elements
+; for rtx-arg-types.
+
+(define -rtx-traverser-table #f)
+
+; Return a hash table of standard operand traversers.
+; The result of each traverser is a pair of the compiled form of `val' and
+; a possibly new traversal state or #f if there is no change.
+
+(define (-rtx-make-traverser-table)
+ (let ((hash-tab (make-hash-table 31))
+ (traversers
+ (list
+ ; /fastcall-make is recognized by Hobbit and handled specially.
+ ; When not using Hobbit it is a macro that returns its argument.
+ (cons 'OPTIONS (/fastcall-make -rtx-traverse-options))
+ (cons 'ANYMODE (/fastcall-make -rtx-traverse-anymode))
+ (cons 'INTMODE (/fastcall-make -rtx-traverse-intmode))
+ (cons 'FLOATMODE (/fastcall-make -rtx-traverse-floatmode))
+ (cons 'NUMMODE (/fastcall-make -rtx-traverse-nummode))
+ (cons 'EXPLNUMMODE (/fastcall-make -rtx-traverse-explnummode))
+ (cons 'NONVOIDFLTODE (/fastcall-make -rtx-traverse-nonvoidmode))
+ (cons 'VOIDFLTODE (/fastcall-make -rtx-traverse-voidmode))
+ (cons 'DFLTMODE (/fastcall-make -rtx-traverse-dfltmode))
+ (cons 'RTX (/fastcall-make -rtx-traverse-rtx))
+ (cons 'SETRTX (/fastcall-make -rtx-traverse-setrtx))
+ (cons 'TESTRTX (/fastcall-make -rtx-traverse-testrtx))
+ (cons 'CONDRTX (/fastcall-make -rtx-traverse-condrtx))
+ (cons 'CASERTX (/fastcall-make -rtx-traverse-casertx))
+ (cons 'LOCALS (/fastcall-make -rtx-traverse-locals))
+ (cons 'ENV (/fastcall-make -rtx-traverse-env))
+ (cons 'ATTRS (/fastcall-make -rtx-traverse-attrs))
+ (cons 'SYMBOL (/fastcall-make -rtx-traverse-symbol))
+ (cons 'STRING (/fastcall-make -rtx-traverse-string))
+ (cons 'NUMBER (/fastcall-make -rtx-traverse-number))
+ (cons 'SYMORNUM (/fastcall-make -rtx-traverse-symornum))
+ (cons 'OBJECT (/fastcall-make -rtx-traverse-object))
+ )))
+
+ (for-each (lambda (traverser)
+ (hashq-set! hash-tab (car traverser) (cdr traverser)))
+ traversers)
+
+ hash-tab)
+)
+
+; Traverse the operands of EXPR, a canonicalized RTL expression.
+; Here "canonicalized" means that -rtx-munge-mode&options has been called to
+; insert an option list and mode if they were absent in the original
+; expression.
+
+(define (-rtx-traverse-operands rtx-obj expr tstate appstuff)
+ (if -rtx-traverse-debug?
+ (begin
+ (display (spaces (* 4 (tstate-depth tstate))))
+ (display "Traversing operands of: ")
+ (display (rtx-dump expr))
+ (newline)
+ (rtx-env-dump (tstate-env tstate))
+ (force-output)
+ ))
+
+ (let loop ((operands (cdr expr))
+ (op-num 0)
+ (arg-types (vector-ref -rtx-traverser-table (rtx-num rtx-obj)))
+ (arg-modes (rtx-arg-modes rtx-obj))
+ (result nil)
+ )
+
+ (let ((varargs? (and (pair? arg-types) (symbol? (car arg-types)))))
+
+ (if -rtx-traverse-debug?
+ (begin
+ (display (spaces (* 4 (tstate-depth tstate))))
+ (if (null? operands)
+ (display "end of operands")
+ (begin
+ (display "op-num ") (display op-num) (display ": ")
+ (display (rtx-dump (car operands)))
+ (display ", ")
+ (display (if varargs? (car arg-types) (caar arg-types)))
+ (display ", ")
+ (display (if varargs? arg-modes (car arg-modes)))
+ ))
+ (newline)
+ (force-output)
+ ))
+
+ (cond ((null? operands)
+ ; Out of operands, check if we have the expected number.
+ (if (or (null? arg-types)
+ varargs?)
+ (reverse! result)
+ (context-error (tstate-context tstate)
+ "missing operands" (rtx-strdump expr))))
+
+ ((null? arg-types)
+ (context-error (tstate-context tstate)
+ "too many operands" (rtx-strdump expr)))
+
+ (else
+ (let ((type (if varargs? arg-types (car arg-types)))
+ (mode (let ((mode-spec (if varargs?
+ arg-modes
+ (car arg-modes))))
+ ; This is small enough that this is fast enough,
+ ; and the number of entries should be stable.
+ ; FIXME: for now
+ (case mode-spec
+ ((ANY) 'DFLT)
+ ((NA) #f)
+ ((OP0) (rtx-mode expr))
+ ((MATCH1)
+ ; If there is an explicit mode, use it.
+ ; Otherwise we have to look at operand 1.
+ (if (eq? (rtx-mode expr) 'DFLT)
+ 'DFLT
+ (rtx-mode expr)))
+ ((MATCH2)
+ ; If there is an explicit mode, use it.
+ ; Otherwise we have to look at operand 2.
+ (if (eq? (rtx-mode expr) 'DFLT)
+ 'DFLT
+ (rtx-mode expr)))
+ (else mode-spec))))
+ (val (car operands))
+ )
+
+ ; Look up the traverser for this kind of operand and perform it.
+ (let ((traverser (cdr type)))
+ (let ((traversed-val (fastcall6 traverser val mode expr op-num tstate appstuff)))
+ (if traversed-val
+ (begin
+ (set! val (car traversed-val))
+ (set! tstate (cdr traversed-val))))))
+
+ ; Done with this operand, proceed to the next.
+ (loop (cdr operands)
+ (+ op-num 1)
+ (if varargs? arg-types (cdr arg-types))
+ (if varargs? arg-modes (cdr arg-modes))
+ (cons val result)))))))
+)
+
+; Publically accessible version of -rtx-traverse-operands as EXPR-FN may
+; need to call it.
+
+(define rtx-traverse-operands -rtx-traverse-operands)
+
+; Subroutine of -rtx-munge-mode&options.
+; Return boolean indicating if X is an rtx option.
+
+(define (-rtx-option? x)
+ (and (symbol? x)
+ (char=? (string-ref x 0) #\:))
+)
+
+; Subroutine of -rtx-munge-mode&options.
+; Return boolean indicating if X is an rtx option list.
+
+(define (-rtx-option-list? x)
+ (or (null? x)
+ (and (pair? x)
+ (-rtx-option? (car x))))
+)
+
+; Subroutine of -rtx-traverse-expr to fill in the mode if absent and to
+; collect the options into one list.
+; ARGS is the list of arguments to the rtx function
+; (e.g. (1 2) in (add 1 2)).
+; ??? "munge" is an awkward name to use here, but I like it for now because
+; it's easy to grep for.
+; ??? An empty option list requires a mode to be present so that the empty
+; list in `(sequence () foo bar)' is unambiguously recognized as the locals
+; list. Icky, sure, but less icky than the alternatives thus far.
+
+(define (-rtx-munge-mode&options args)
+ (let ((options nil)
+ (mode-name 'DFLT))
+ ; Pick off the option list if present.
+ (if (and (pair? args)
+ (-rtx-option-list? (car args))
+ ; Handle `(sequence () foo bar)'. If empty list isn't followed
+ ; by a mode, it is not an option list.
+ (or (not (null? (car args)))
+ (and (pair? (cdr args))
+ (mode-name? (cadr args)))))
+ (begin
+ (set! options (car args))
+ (set! args (cdr args))))
+ ; Pick off the mode if present.
+ (if (and (pair? args)
+ (mode-name? (car args)))
+ (begin
+ (set! mode-name (car args))
+ (set! args (cdr args))))
+ ; Now put option list and mode back.
+ (cons options (cons mode-name args)))
+)
+
+; Traverse an expression.
+; For syntax expressions arguments are not pre-evaluated before calling the
+; user's expression handler. Otherwise they are.
+; If EXPR-FN wants to just scan the operands, rather than evaluating them,
+; one thing it can do is call back to rtx-traverse-operands.
+; If EXPR-FN returns #f, traverse the operands normally and return
+; (rtx's-name traversed-operand1 ...).
+; This is for semantic-compile's sake and all traversal handlers are
+; required to do this if EXPR-FN returns #f.
+
+(define (-rtx-traverse-expr rtx-obj expr mode parent-expr op-pos tstate appstuff)
+ (let* ((expr2 (cons (car expr)
+ (-rtx-munge-mode&options (cdr expr))))
+ (fn (fastcall7 (tstate-expr-fn tstate)
+ rtx-obj expr2 mode parent-expr op-pos tstate appstuff)))
+ (if fn
+ (if (procedure? fn)
+ ; Don't traverse operands for syntax expressions.
+ (if (rtx-style-syntax? rtx-obj)
+ (apply fn (cons tstate (cdr expr2)))
+ (let ((operands (-rtx-traverse-operands rtx-obj expr2 tstate appstuff)))
+ (apply fn (cons tstate operands))))
+ fn)
+ (let ((operands (-rtx-traverse-operands rtx-obj expr2 tstate appstuff)))
+ (cons (car expr2) operands))))
+)
+
+; Main entry point for expression traversal.
+; (Actually rtx-traverse is, but it's just a cover function for this.)
+;
+; The result is the result of the lambda EXPR-FN looks up in the case of
+; expressions or an operand object (usually <operand>) in the case of operands.
+;
+; EXPR is the expression to be traversed.
+;
+; MODE is the name of the mode of EXPR.
+;
+; PARENT-EXPR is the expression EXPR is contained in. The top-level
+; caller must pass #f for it.
+;
+; OP-POS is the position EXPR appears in PARENT-EXPR. The
+; top-level caller must pass 0 for it.
+;
+; EXPECTED is one of `-rtx-valid-types' and indicates the expected rtx type
+; or #f if it doesn't matter.
+;
+; TSTATE is the current traversal state.
+;
+; APPSTUFF is for application specific use.
+;
+; All macros are expanded here. User code never sees them.
+; All operand shortcuts are also expand here. User code never sees them.
+; These are:
+; - operands, ifields, and numbers appearing where an rtx is expected are
+; converted to use `operand', `ifield', or `const'.
+
+(define (-rtx-traverse expr expected mode parent-expr op-pos tstate appstuff)
+ (if -rtx-traverse-debug?
+ (begin
+ (display (spaces (* 4 (tstate-depth tstate))))
+ (display "Traversing expr: ")
+ (display expr)
+ (newline)
+ (display (spaces (* 4 (tstate-depth tstate))))
+ (display "-expected: ")
+ (display expected)
+ (newline)
+ (display (spaces (* 4 (tstate-depth tstate))))
+ (display "-mode: ")
+ (display mode)
+ (newline)
+ (force-output)
+ ))
+
+ (if (pair? expr) ; pair? -> cheap non-null-list?
+
+ (let ((rtx-obj (rtx-lookup (car expr))))
+ (tstate-incr-depth! tstate)
+ (let ((result
+ (if rtx-obj
+ (-rtx-traverse-expr rtx-obj expr mode parent-expr op-pos tstate appstuff)
+ (let ((rtx-obj (-rtx-macro-lookup (car expr))))
+ (if rtx-obj
+ (-rtx-traverse (-rtx-macro-expand expr rtx-evaluator)
+ expected mode parent-expr op-pos tstate appstuff)
+ (context-error (tstate-context tstate) "unknown rtx function"
+ expr))))))
+ (tstate-decr-depth! tstate)
+ result))
+
+ ; EXPR is not a list.
+ ; See if it's an operand shortcut.
+ (if (memq expected '(RTX SETRTX))
+
+ (cond ((symbol? expr)
+ (cond ((current-op-lookup expr)
+ (-rtx-traverse
+ (rtx-make-operand expr) ; (current-op-lookup expr))
+ expected mode parent-expr op-pos tstate appstuff))
+ ((rtx-temp-lookup (tstate-env tstate) expr)
+ (-rtx-traverse
+ (rtx-make-local expr) ; (rtx-temp-lookup (tstate-env tstate) expr))
+ expected mode parent-expr op-pos tstate appstuff))
+ ((current-ifld-lookup expr)
+ (-rtx-traverse
+ (rtx-make-ifield expr)
+ expected mode parent-expr op-pos tstate appstuff))
+ ((enum-lookup-val expr)
+ (-rtx-traverse
+ (rtx-make-enum 'INT expr)
+ expected mode parent-expr op-pos tstate appstuff))
+ (else
+ (context-error (tstate-context tstate)
+ "unknown operand" expr))))
+ ((integer? expr)
+ (-rtx-traverse (rtx-make-const 'INT expr)
+ expected mode parent-expr op-pos tstate appstuff))
+ (else
+ (context-error (tstate-context tstate)
+ "unexpected operand"
+ expr)))
+
+ ; Not expecting RTX or SETRTX.
+ (context-error (tstate-context tstate)
+ "unexpected operand"
+ expr)))
+)
+
+; User visible procedures to traverse an rtl expression.
+; These calls -rtx-traverse to do most of the work.
+; See tstate-make for an explanation of EXPR-FN.
+; CONTEXT is a <context> object or #f if there is none.
+; LOCALS is a list of (mode . name) elements (the locals arg to `sequence').
+; APPSTUFF is for application specific use.
+
+(define (rtx-traverse context owner expr expr-fn appstuff)
+ (-rtx-traverse expr #f 'DFLT #f 0
+ (tstate-make context owner expr-fn (rtx-env-empty-stack)
+ #f #f nil 0)
+ appstuff)
+)
+
+(define (rtx-traverse-with-locals context owner expr expr-fn locals appstuff)
+ (-rtx-traverse expr #f 'DFLT #f 0
+ (tstate-make context owner expr-fn
+ (rtx-env-push (rtx-env-empty-stack)
+ (rtx-env-make-locals locals))
+ #f #f nil 0)
+ appstuff)
+)
+
+; Traverser debugger.
+
+(define (rtx-traverse-debug expr)
+ (rtx-traverse
+ #f #f expr
+ (lambda (rtx-obj expr mode parent-expr op-pos tstate appstuff)
+ (display "-expr: ")
+ (display (string-append "rtx=" (obj:name rtx-obj)))
+ (display " expr=")
+ (display expr)
+ (display " mode=")
+ (display mode)
+ (display " parent=")
+ (display parent-expr)
+ (display " op-pos=")
+ (display op-pos)
+ (display " cond?=")
+ (display (tstate-cond? tstate))
+ (newline)
+ #f)
+ #f
+ )
+)
+
+; Convert rtl expression EXPR from source form to compiled form.
+; The expression is validated and rtx macros are expanded as well.
+; CONTEXT is a <context> object or #f if there is none.
+; It is used in error messages.
+; EXTRA-VARS-ALIST is an association list of extra (symbol <mode> value)
+; elements to be used during value lookup.
+;
+; This does the same operation that rtx-traverse does, except that it provides
+; a standard value for EXPR-FN.
+;
+; ??? In the future the compiled form may be the same as the source form
+; except that all elements would be converted to their respective objects.
+
+(define (-compile-expr-fn rtx-obj expr mode parent-expr op-pos tstate appstuff)
+; (cond
+; The intent of this is to handle sequences/closures, but is it needed?
+; ((rtx-style-syntax? rtx-obj)
+; ((rtx-evaluator rtx-obj) rtx-obj expr mode
+; parent-expr op-pos tstate))
+; (else
+ (cons (car expr) ; rtx-obj
+ (-rtx-traverse-operands rtx-obj expr tstate appstuff))
+)
+
+(define (rtx-compile context expr extra-vars-alist)
+ (-rtx-traverse expr #f 'DFLT #f 0
+ (tstate-make context #f
+ (/fastcall-make -compile-expr-fn)
+ (rtx-env-init-stack1 extra-vars-alist)
+ #f #f nil 0)
+ #f)
+)
+
+; Various rtx utilities.
+
+; Dump an rtx expression.
+
+(define (rtx-dump rtx)
+ (cond ((list? rtx) (map rtx-dump rtx))
+ ((object? rtx) (string-append "#<object "
+ (object-class-name rtx)
+ " "
+ (obj:name rtx)
+ ">"))
+ (else rtx))
+)
+
+; Dump an expression to a string.
+
+(define (rtx-strdump rtx)
+ (with-output-to-string
+ (lambda ()
+ (display (rtx-dump rtx))))
+)
+
+; Return a boolean indicating if EXPR is known to be a compile-time constant.
+
+(define (rtx-compile-time-constant? expr)
+ (cond ((pair? expr)
+ (case (car expr)
+ ((const enum) #t)
+ (else #f)))
+ ((memq expr '(FALSE TRUE)) #t)
+ (else #f))
+)
+
+; Return boolean indicating if EXPR has side-effects.
+; FIXME: for now punt.
+
+(define (rtx-side-effects? expr)
+ #f
+)
+
+; Return a boolean indicating if EXPR is a "true" boolean value.
+;
+; ??? In RTL, #t is a synonym for (const 1). This is confusing for Schemers,
+; so maybe RTL's #t should be renamed to TRUE.
+
+(define (rtx-true? expr)
+ (cond ((pair? expr)
+ (case (car expr)
+ ((const enum) (!= (rtx-constant-value expr) 0))
+ (else #f)))
+ ((eq? expr 'TRUE) #t)
+ (else #f))
+)
+
+; Return a boolean indicating if EXPR is a "false" boolean value.
+;
+; ??? In RTL, #f is a synonym for (const 0). This is confusing for Schemers,
+; so maybe RTL's #f should be renamed to FALSE.
+
+(define (rtx-false? expr)
+ (cond ((pair? expr)
+ (case (car expr)
+ ((const enum) (= (rtx-constant-value expr) 0))
+ (else #f)))
+ ((eq? expr 'FALSE) #t)
+ (else #f))
+)
+
+; Return canonical boolean values.
+
+(define (rtx-false) (rtx-make-const 'BI 0))
+(define (rtx-true) (rtx-make-const 'BI 1))
+
+; Convert EXPR to a canonical boolean if possible.
+
+(define (rtx-canonical-bool expr)
+ (cond ((rtx-side-effects? expr) expr)
+ ((rtx-false? expr) (rtx-false))
+ ((rtx-true? expr) (rtx-true))
+ (else expr))
+)
+
+; Return rtx values for #f/#t.
+
+(define (rtx-make-bool value)
+ (if value
+ (rtx-true)
+ (rtx-false))
+)
+
+; Return #t if X is an rtl expression.
+; e.g. '(add WI dr simm8);
+
+(define (rtx? x)
+ (->bool
+ (and (pair? x) ; pair? -> cheap non-null-list?
+ (or (hashq-ref -rtx-func-table (car x))
+ (hashq-ref -rtx-macro-table (car x)))))
+)
+
+; RTL evaluation state.
+; Applications may subclass <eval-state> if they need to add things.
+;
+; This is initialized before evaluation, and modified (in a copy) as the
+; evaluation state changes.
+; This doesn't record all evaluation state, just the less dynamic elements.
+; There's no point in recording things like the parent expression and operand
+; position as they change for every sub-eval.
+; The main raison d'etre for this class is so we can add more state without
+; having to modify all the eval handlers.
+
+(define <eval-state>
+ (class-make '<eval-state> nil
+ '(
+ ; <context> object or #f if there is none
+ (context . #f)
+
+ ; Current object rtl is being evaluated for.
+ ; We need to be able to access the current instruction while
+ ; generating semantic code. However, the semantic description
+ ; doesn't specify it as an argument to anything (and we don't
+ ; want it to). So we record the value here.
+ (owner . #f)
+
+ ; EXPR-FN is a dual-purpose beast. The first purpose is to
+ ; just process the current expression and return the result.
+ ; The second purpose is to lookup the function which will then
+ ; process the expression. It is applied recursively to the
+ ; expression and each sub-expression. It must be defined as
+ ; (lambda (rtx-obj expr mode estate) ...).
+ ; If the result of EXPR-FN is a lambda, it is applied to
+ ; (cons ESTATE (cdr EXPR)). ESTATE is prepended to the
+ ; arguments.
+ ; For syntax expressions if the result of EXPR-FN is #f,
+ ; the operands are processed using the builtin evaluator.
+ ; FIXME: This special handling of syntax expressions is
+ ; not currently done.
+ ; So to repeat: EXPR-FN can process the expression, and if its
+ ; result is a lambda then it also processes the expression.
+ ; The arguments to EXPR-FN are
+ ; (rtx-obj expr mode estate).
+ ; The arguments to the result of EXPR-FN are
+ ; (cons ESTATE (cdr EXPR)).
+ ; The reason for the duality is mostly history.
+ ; In time things should be simplified.
+ (expr-fn . #f)
+
+ ; Current environment. This is a stack of sequence locals.
+ (env . ())
+
+ ; Current evaluation depth. This is used, for example, to
+ ; control indentation in generated output.
+ (depth . 0)
+
+ ; Associative list of modifiers.
+ ; This is here to support things like `delay'.
+ (modifiers . ())
+ )
+ nil)
+)
+
+; Create an <eval-state> object using a list of keyword/value elements.
+; ARGS is a list of #:keyword/value elements.
+; The result is a list of the unrecognized elements.
+; Subclasses should override this method and send-next it first, then
+; see if they recognize anything in the result, returning what isn't
+; recognized.
+
+(method-make!
+ <eval-state> 'vmake!
+ (lambda (self args)
+ (let loop ((args args) (unrecognized nil))
+ (if (null? args)
+ (reverse! unrecognized) ; ??? Could invoke method to initialize here.
+ (begin
+ (case (car args)
+ ((#:context)
+ (elm-set! self 'context (cadr args)))
+ ((#:owner)
+ (elm-set! self 'owner (cadr args)))
+ ((#:expr-fn)
+ (elm-set! self 'expr-fn (cadr args)))
+ ((#:env)
+ (elm-set! self 'env (cadr args)))
+ ((#:depth)
+ (elm-set! self 'depth (cadr args)))
+ ((#:modifiers)
+ (elm-set! self 'modifiers (cadr args)))
+ (else
+ ; Build in reverse order, as we reverse it back when we're done.
+ (set! unrecognized
+ (cons (cadr args) (cons (car args) unrecognized)))))
+ (loop (cddr args) unrecognized)))))
+)
+
+; Accessors.
+
+(define-getters <eval-state> estate
+ (context owner expr-fn env depth modifiers)
+)
+(define-setters <eval-state> estate
+ (context owner expr-fn env depth modifiers)
+)
+
+; Build an estate for use in producing a value from rtl.
+; CONTEXT is a <context> object or #f if there is none.
+; OWNER is the owner of the expression or #f if there is none.
+
+(define (estate-make-for-eval context owner)
+ (vmake <eval-state>
+ #:context context
+ #:owner owner
+ #:expr-fn (lambda (rtx-obj expr mode estate)
+ (rtx-evaluator rtx-obj)))
+)
+
+; Create a copy of ESTATE.
+
+(define (estate-copy estate)
+ (object-copy-top estate)
+)
+
+; Create a copy of STATE with a new environment ENV.
+
+(define (estate-new-env state env)
+ (let ((result (estate-copy state)))
+ (estate-set-env! result env)
+ result)
+)
+
+; Create a copy of STATE with environment ENV pushed onto the existing
+; environment list.
+; There's no routine to pop the environment list as there's no current
+; need for it: we make a copy of the state when we push.
+
+(define (estate-push-env state env)
+ (let ((result (estate-copy state)))
+ (estate-set-env! result (cons env (estate-env result)))
+ result)
+)
+
+; Create a copy of STATE with modifiers MODS.
+
+(define (estate-with-modifiers state mods)
+ (let ((result (estate-copy state)))
+ (estate-set-modifiers! result (append mods (estate-modifiers result)))
+ result)
+)
+
+; Convert a tstate to an estate.
+
+(define (tstate->estate t)
+ (vmake <eval-state>
+ #:context (tstate-context t)
+ #:env (tstate-env t))
+)
+
+; RTL expression evaluation.
+;
+; ??? These used eval2 at one point. Not sure which is faster but I suspect
+; eval2 is by far. On the otherhand this has yet to be compiled. And this way
+; is more portable, more flexible, and works with guile 1.2 (which has
+; problems with eval'ing self referential vectors, though that's one reason to
+; use smobs).
+
+; Set to #t to debug rtx evaluation.
+
+(define -rtx-eval-debug? #f)
+
+; RTX expression evaluator.
+;
+; EXPR is the expression to be eval'd. It must be in compiled form.
+; MODE is the mode of EXPR, a <mode> object or its name.
+; ESTATE is the current evaluation state.
+
+(define (rtx-eval-with-estate expr mode estate)
+ (if -rtx-eval-debug?
+ (begin
+ (display "Traversing ")
+ (display expr)
+ (newline)
+ (rtx-env-dump (estate-env estate))
+ ))
+
+ (if (pair? expr) ; pair? -> cheap non-null-list?
+
+ (let* ((rtx-obj (rtx-lookup (car expr)))
+ (fn ((estate-expr-fn estate) rtx-obj expr mode estate)))
+ (if fn
+ (if (procedure? fn)
+ (apply fn (cons estate (cdr expr)))
+; ; Don't eval operands for syntax expressions.
+; (if (rtx-style-syntax? rtx-obj)
+; (apply fn (cons estate (cdr expr)))
+; (let ((operands
+; (-rtx-eval-operands rtx-obj expr estate)))
+; (apply fn (cons estate operands))))
+ fn)
+ ; Leave expr unchanged.
+ expr))
+; (let ((operands
+; (-rtx-traverse-operands rtx-obj expr estate)))
+; (cons rtx-obj operands))))
+
+ ; EXPR is not a list
+ (error "argument to rtx-eval-with-estate is not a list" expr))
+)
+
+; Evaluate rtx expression EXPR and return the computed value.
+; EXPR must already be in compiled form (the result of rtx-compile).
+; OWNER is the owner of the value, used for attribute computation,
+; or #f if there isn't one.
+; FIXME: context?
+
+(define (rtx-value expr owner)
+ (rtx-eval-with-estate expr 'DFLT (estate-make-for-eval #f owner))
+)
+
+; Instruction field support.
+
+; Return list of ifield names refered to in EXPR.
+; Assumes EXPR is more than just (ifield x).
+
+(define (rtl-find-ifields expr)
+ (let ((ifields nil))
+ (letrec ((scan! (lambda (arg-list)
+ (for-each (lambda (arg)
+ (if (pair? arg)
+ (if (eq? (car arg) 'ifield)
+ (set! ifields
+ (cons (rtx-ifield-name arg)
+ ifields))
+ (scan! (cdr arg)))))
+ arg-list))))
+ (scan! (cdr expr))
+ (nub ifields identity)))
+)
+
+; Hardware rtx handlers.
+
+; Subroutine of hw to compute the object's name.
+; The name of the operand must include the index so that multiple copies
+; of a hardware object (e.g. h-gr[0], h-gr[14]) can be distinguished.
+; We make some attempt to make the name pretty as it appears in generated
+; files.
+
+(define (-rtx-hw-name hw hw-name index-arg)
+ (cond ((hw-scalar? hw)
+ hw-name)
+ ((rtx? index-arg)
+ (symbol-append hw-name '- (rtx-pretty-name index-arg)))
+ (else
+ (symbol-append hw-name ; (obj:name (op:type self))
+ '-
+ ; (obj:name (op:index self)))))
+ (stringize index-arg "-"))))
+)
+
+; Return the <operand> object described by
+; HW-NAME/MODE-NAME/SELECTOR/INDEX-ARG.
+;
+; HW-NAME is the name of the hardware element.
+; INDEX-ARG is an rtx or number of the index.
+; In the case of scalar hardware elements, pass 0 for INDEX-ARG.
+; MODE-NAME is the name of the mode.
+; In the case of a vector of registers, INDEX-ARG is the vector index.
+; In the case of a scalar register, the value is ignored, but pass 0 (??? #f?).
+; SELECTOR is an rtx or number and is passed to HW-NAME to allow selection of a
+; particular variant of the hardware. It's kind of like an INDEX, but along
+; an atypical axis. An example is memory ASI's on Sparc. Pass
+; hw-selector-default if there is no selector.
+; ESTATE is the current rtx evaluation state.
+;
+; e.g. (hw estate WI h-gr #f (const INT 14))
+; selects register 14 of the h-gr set of registers.
+;
+; *** The index is passed unevaluated because for parallel execution support
+; *** a variable is created with a name based on the hardware element and
+; *** index, and we want a reasonably simple and stable name. We get this by
+; *** stringize-ing it.
+; *** ??? Though this needs to be redone anyway.
+;
+; ??? The specified hardware element must be either a scalar or a vector.
+; Maybe in the future allow arrays although there's significant utility in
+; allowing only at most a scalar index.
+
+(define (hw estate mode-name hw-name index-arg selector)
+ ; Enforce some rules to keep things in line with the current design.
+ (if (not (symbol? mode-name))
+ (parse-error "hw" "invalid mode name" mode-name))
+ (if (not (symbol? hw-name))
+ (parse-error "hw" "invalid hw name" hw-name))
+ (if (not (or (number? index-arg)
+ (rtx? index-arg)))
+ (parse-error "hw" "invalid index" index-arg))
+ (if (not (or (number? selector)
+ (rtx? selector)))
+ (parse-error "hw" "invalid selector" selector))
+
+ (let ((hw (current-hw-sem-lookup-1 hw-name)))
+ (if (not hw)
+ (parse-error "hw" "invalid hardware element" hw-name))
+
+ (let ((mode (if (eq? mode-name 'DFLT) (hw-mode hw) (mode:lookup mode-name)))
+ (result (new <operand>))) ; ??? lookup-for-new?
+
+ (if (not mode)
+ (parse-error "hw" "invalid mode" mode-name))
+
+ ; Record the selector.
+ (elm-xset! result 'selector selector)
+
+ ; Create the index object.
+ (elm-xset! result 'index
+ (cond ((number? index-arg)
+ (make <hw-index> 'anonymous 'constant UINT index-arg))
+ ((rtx? index-arg)
+ ; For the simulator the following could be done which
+ ; would save having to create a closure.
+ ; ??? Old code, left in for now.
+ ; (rtx-get estate DFLT
+ ; (rtx-eval (estate-context estate)
+ ; (estate-econfig estate)
+ ; index-arg rtx-evaluator))
+ ; Make sure constant indices are recorded as such.
+ (if (rtx-constant? index-arg)
+ (make <hw-index> 'anonymous 'constant UINT
+ (rtx-constant-value index-arg))
+ (make <hw-index> 'anonymous 'rtx DFLT
+ (-rtx-closure-make estate index-arg))))
+ (else (parse-error "hw" "invalid index" index-arg))))
+
+ (if (not (hw-mode-ok? hw (obj:name mode) (elm-xget result 'index)))
+ (parse-error "hw" "invalid mode for hardware" mode-name))
+
+ (elm-xset! result 'type hw)
+ (elm-xset! result 'mode mode)
+
+ ; The name of the operand must include the index so that multiple copies
+ ; of a hardware object (e.g. h-gr[0], h-gr[14]) can be distinguished.
+ (let ((name (-rtx-hw-name hw hw-name index-arg)))
+ (send result 'set-name! name)
+ (op:set-sem-name! result name))
+
+ ; Empty comment and attribute.
+ ; ??? Stick the arguments in the comment for debugging purposes?
+ (send result 'set-comment! "")
+ (send result 'set-atlist! atlist-empty)
+
+ result))
+)
+
+; This is shorthand for (hw estate mode hw-name regno selector).
+; ESTATE is the current rtx evaluation state.
+; INDX-SEL is an optional register number and possible selector.
+; The register number, if present, is (car indx-sel) and must be a number or
+; unevaluated RTX expression.
+; The selector, if present, is (cadr indx-sel) and must be a number or
+; unevaluated RTX expression.
+; ??? A register selector isn't supported yet. It's just an idea that's
+; been put down on paper for future reference.
+
+(define (reg estate mode hw-name . indx-sel)
+ (s-hw estate mode hw-name
+ (if (pair? indx-sel) (car indx-sel) 0)
+ (if (and (pair? indx-sel) (pair? (cdr indx-sel)))
+ (cadr indx-sel)
+ hw-selector-default))
+)
+
+; This is shorthand for (hw estate mode h-memory addr selector).
+; ADDR must be an unevaluated RTX expression.
+; If present (car sel) must be a number or unevaluated RTX expression.
+
+(define (mem estate mode addr . sel)
+ (s-hw estate mode 'h-memory addr
+ (if (pair? sel) (car sel) hw-selector-default))
+)
+
+; For the rtx nodes to use.
+
+(define s-hw hw)
+
+; The program counter.
+; When this code is loaded, global `pc' is nil, it hasn't been set to the
+; pc operand yet (see operand-init!). We can't use `pc' inside the drn as the
+; value is itself. So we use s-pc. rtl-finish! must be called after
+; operand-init!.
+
+(define s-pc pc)
+
+; Conditional execution.
+
+; `if' in RTL has a result, like ?: in C.
+; We support both: one with a result (non VOID mode), and one without (VOID mode).
+; The non-VOID case must have an else part.
+; MODE is the mode of the result, not the comparison.
+; The comparison is expected to return a zero/non-zero value.
+; ??? Perhaps this should be a syntax-expr. Later.
+
+(define (e-if estate mode cond then . else)
+ (if (> (length else) 1)
+ (error "if: too many elements in `else' part" else))
+ (if (null? else)
+ (if cond then)
+ (if cond then (car else)))
+)
+
+; Subroutines.
+; ??? Not sure this should live here.
+
+(define (-subr-read errtxt . arg-list)
+ #f
+)
+
+(define define-subr
+ (lambda arg-list
+ (let ((s (apply -subr-read (cons "define-subr" arg-list))))
+ (if s
+ (current-subr-add! s))
+ s))
+)
+
+; Misc. utilities.
+
+; The argument to drn,drmn,drsn must be Scheme code (or a fixed subset
+; thereof). .str/.sym are used in pmacros so it makes sense to include them
+; in the subset.
+(define .str string-append)
+(define .sym symbol-append)
+
+; Given (expr1 expr2 expr3 expr4), for example,
+; return (fn (fn (fn expr1 expr2) expr3) expr4).
+
+(define (rtx-combine fn exprs)
+ (assert (not (null? exprs)))
+ (letrec ((-rtx-combine (lambda (fn exprs result)
+ (if (null? exprs)
+ result
+ (-rtx-combine fn
+ (cdr exprs)
+ (rtx-make fn
+ result
+ (car exprs)))))))
+ (-rtx-combine fn (cdr exprs) (car exprs)))
+)
+
+; Called before a .cpu file is read in.
+
+(define (rtl-init!)
+ (set! -rtx-func-table (make-hash-table 127))
+ (set! -rtx-macro-table (make-hash-table 127))
+ (set! -rtx-num-next 0)
+ (def-rtx-funcs)
+ (reader-add-command! 'define-subr
+ "\
+Define an rtx subroutine, name/value pair list version.
+"
+ nil 'arg-list define-subr)
+ *UNSPECIFIED*
+)
+
+; Install builtins
+
+(define (rtl-builtin!)
+ *UNSPECIFIED*
+)
+
+; Called after cpu files are loaded to add misc. remaining entries to the
+; rtx handler table for use during evaluation.
+; rtl-finish! must be done before ifmt-compute!, the latter will
+; construct hardware objects which is done by rtx evaluation.
+
+(define (rtl-finish!)
+ (logit 2 "Building rtx operand table ...\n")
+
+ ; Update s-pc, must be called after operand-init!.
+ (set! s-pc pc)
+
+ ; Table of traversers for the various rtx elements.
+ (let ((hash-table (-rtx-make-traverser-table)))
+ (set! -rtx-traverser-table (make-vector (rtx-max-num) #f))
+ (for-each (lambda (rtx-name)
+ (let ((rtx (rtx-lookup rtx-name)))
+ (if rtx
+ (vector-set! -rtx-traverser-table (rtx-num rtx)
+ (map1-improper
+ (lambda (arg-type)
+ (cons arg-type
+ (hashq-ref hash-table arg-type)))
+ (rtx-arg-types rtx))))))
+ (rtx-name-list)))
+
+ ; Initialize the operand hash table.
+ (set! -rtx-operand-table (make-hash-table 127))
+
+ ; Add the operands to the eval symbol table.
+ (for-each (lambda (op)
+ (hashq-set! -rtx-operand-table (obj:name op) op)
+ )
+ (current-op-list))
+
+ ; Add ifields to the eval symbol table.
+ (for-each (lambda (f)
+ (hashq-set! -rtx-operand-table (obj:name f) f)
+ )
+ (non-derived-ifields (current-ifld-list)))
+
+ *UNSPECIFIED*
+)