2 ; Copyright (C) 2000, 2001 Red Hat, Inc.
3 ; This file is part of CGEN.
4 ; See file COPYING.CGEN for details.
6 ; The name for the description language has been changed a couple of times.
7 ; RTL isn't my favorite because of perceived confusion with GCC
8 ; (and perceived misinterpretation of intentions!).
9 ; On the other hand my other choices were taken (and believed to be
12 ; RTL functions are described by class <rtx-func>.
13 ; The complete list of rtl functions is defined in doc/rtl.texi.
15 ; Conventions used in this file:
16 ; - procs that perform the basic rtl or semantic expression manipulation that
17 ; is for public use shall be prefixed with "s-" or "rtl-" or "rtx-"
18 ; - no other procs shall be so prefixed
19 ; - rtl globals and other rtx-func object support shall be prefixed with
21 ; - no other procs shall be so prefixed
23 ; Class for defining rtx nodes.
25 ; FIXME: Add new members that are lambda's to perform the argument checking
26 ; specified by `arg-types' and `arg-modes'. This will save a lookup during
27 ; traversing. It will also allow custom versions for oddballs (e.g. for
28 ; `member' we want to verify the 2nd arg is a `number-list' rtx).
32 (class-make '<rtx-func> nil
34 ; name as it appears in RTL
40 ; types of each argument, as symbols
41 ; This is #f for macros.
43 ; OPTIONS - optional list of :-prefixed options.
45 ; INTMODE - any integer mode
46 ; FLOATMODE - any floating point mode
47 ; NUMMODE - any numeric mode
48 ; EXPLNUMMODE - explicit numeric mode, can't be DFLT or VOID
49 ; NONVOIDMODE - can't be `VOID'
50 ; VOIDMODE - must be `VOID'
51 ; DFLTMODE - must be `DFLT', used when any mode is inappropriate
53 ; SETRTX - any rtx allowed to be `set'
54 ; TESTRTX - the test of an `if'
55 ; CONDRTX - a cond expression ((test) rtx ... rtx)
56 ; CASERTX - a case expression ((symbol .. symbol) rtx ... rtx)
57 ; LOCALS - the locals list of a sequence
58 ; ENV - environment stack
59 ; ATTRS - attribute list
60 ; SYMBOL - operand must be a symbol
61 ; STRING - operand must be a string
62 ; NUMBER - operand must be a number
63 ; SYMORNUM - operand must be a symbol or number
64 ; OBJECT - operand is an object
67 ; required mode of each argument
68 ; This is #f for macros.
69 ; Possible values include any mode name and:
72 ; OP0 - mode is specified in operand 0
73 ; unless it is DFLT in which case use the default mode
75 ; MATCH1 - must match mode of operand 1
76 ; which will have OP0 for its mode spec
77 ; MATCH2 - must match mode of operand 2
78 ; which will have OP0 for its mode spec
79 ; <MODE-NAME> - must match specified mode
83 ; This is #f for macros.
84 ; ARG - operand, local, const
86 ; UNARY - not, inv, etc.
87 ; BINARY - add, sub, etc.
88 ; TRINARY - addc, subc, etc.
91 ; SEQUENCE - sequence, parallel
93 ; MISC - everything else
96 ; A symbol indicating the flavour of rtx node this is.
97 ; function - normal function
98 ; syntax - don't pre-eval arguments
99 ; operand - result is an operand
100 ; macro - converts one rtx expression to another
101 ; The word "style" was chosen to be sufficiently different
102 ; from "type", "kind", and "class".
105 ; A function to perform the rtx.
108 ; Ordinal number of rtx. Used to index into tables.
116 (define (rtx-func? x) (class-instance? <rtx-func> x))
120 (define-getters <rtx-func> rtx
121 (name args arg-types arg-modes class style evaluator num)
124 (define (rtx-class-arg? rtx) (eq? (rtx-class rtx) 'ARG))
125 (define (rtx-class-set? rtx) (eq? (rtx-class rtx) 'SET))
126 (define (rtx-class-unary? rtx) (eq? (rtx-class rtx) 'UNARY))
127 (define (rtx-class-binary? rtx) (eq? (rtx-class rtx) 'BINARY))
128 (define (rtx-class-trinary? rtx) (eq? (rtx-class rtx) 'TRINARY))
129 (define (rtx-class-if? rtx) (eq? (rtx-class rtx) 'IF))
130 (define (rtx-class-cond? rtx) (eq? (rtx-class rtx) 'COND))
131 (define (rtx-class-sequence? rtx) (eq? (rtx-class rtx) 'SEQUENCE))
132 (define (rtx-class-unspec? rtx) (eq? (rtx-class rtx) 'UNSPEC))
133 (define (rtx-class-misc? rtx) (eq? (rtx-class rtx) 'MISC))
135 (define (rtx-style-function? rtx) (eq? (rtx-style rtx) 'function))
136 (define (rtx-style-syntax? rtx) (eq? (rtx-style rtx) 'syntax))
137 (define (rtx-style-operand? rtx) (eq? (rtx-style rtx) 'operand))
138 (define (rtx-style-macro? rtx) (eq? (rtx-style rtx) 'macro))
140 ; Add standard `get-name' method since this isn't a subclass of <ident>.
142 (method-make! <rtx-func> 'get-name (lambda (self) (elm-get self 'name)))
144 ; List of valid values for arg-types, not including mode names.
146 (define -rtx-valid-types
148 ANYMODE INTMODE FLOATMODE NUMMODE EXPLNUMMODE NONVOIDMODE VOIDMODE DFLTMODE
149 RTX TESTRTX CONDRTX CASERTX
150 LOCALS ENV ATTRS SYMBOL STRING NUMBER SYMORNUM OBJECT)
153 ; List of valid mode matchers, excluding mode names.
155 (define -rtx-valid-matches
156 '(ANY NA OP0 MATCH1 MATCH2)
159 ; List of all defined rtx names. This can be map'd over without having
160 ; to know the innards of -rtx-func-table (which is a hash table).
162 (define -rtx-name-list nil)
163 (define (rtx-name-list) -rtx-name-list)
165 ; Table of rtx function objects.
166 ; This is set in rtl-init!.
168 (define -rtx-func-table nil)
170 ; Look up the <rtx-func> object for RTX-KIND.
171 ; Returns the object or #f if not found.
172 ; RTX-KIND may already be an <rtx-func> object. FIXME: delete?
174 (define (rtx-lookup rtx-kind)
175 (cond ((symbol? rtx-kind)
176 (hashq-ref -rtx-func-table rtx-kind))
177 ((rtx-func? rtx-kind)
182 ; Table of rtx macro objects.
183 ; This is set in rtl-init!.
185 (define -rtx-macro-table nil)
187 ; Table of operands, modes, and other non-functional aspects of RTL.
188 ; This is defined in rtl-finish!, after all operands have been read in.
190 (define -rtx-operand-table nil)
192 ; Number of next rtx to be defined.
194 (define -rtx-num-next #f)
196 ; Return the number of rtx's.
198 (define (rtx-max-num)
204 ; Add an entry to the rtx function table.
205 ; NAME-ARGS is a list of the operation name and arguments.
206 ; The mode of the result must be the first element in `args' (if there are
208 ; ARG-TYPES is a list of argument types (-rtx-valid-types).
209 ; ARG-MODES is a list of mode matchers (-rtx-valid-matches).
210 ; ACTION is a list of Scheme expressions to perform the operation.
212 ; ??? Note that we can support variables. Not sure it should be done.
214 (define (def-rtx-node name-args arg-types arg-modes class action)
215 (let ((name (car name-args))
216 (args (cdr name-args)))
217 (let ((rtx (make <rtx-func> name args
222 (eval (list 'lambda (cons '*estate* args) action))
225 ; Add it to the table of rtx handlers.
226 (hashq-set! -rtx-func-table name rtx)
227 (set! -rtx-num-next (+ -rtx-num-next 1))
228 (set! -rtx-name-list (cons name -rtx-name-list))
232 (define define-rtx-node
233 ; Written this way so Hobbit can handle it.
234 (defmacro:syntax-transformer (lambda arg-list
235 (apply def-rtx-node arg-list)
239 ; Same as define-rtx-node but don't pre-evaluate the arguments.
240 ; Remember that `mode' must be the first argument.
242 (define (def-rtx-syntax-node name-args arg-types arg-modes class action)
243 (let ((name (car name-args))
244 (args (cdr name-args)))
245 (let ((rtx (make <rtx-func> name args
250 (eval (list 'lambda (cons '*estate* args) action))
253 ; Add it to the table of rtx handlers.
254 (hashq-set! -rtx-func-table name rtx)
255 (set! -rtx-num-next (+ -rtx-num-next 1))
256 (set! -rtx-name-list (cons name -rtx-name-list))
260 (define define-rtx-syntax-node
261 ; Written this way so Hobbit can handle it.
262 (defmacro:syntax-transformer (lambda arg-list
263 (apply def-rtx-syntax-node arg-list)
267 ; Same as define-rtx-node but return an operand (usually an <operand> object).
268 ; ??? `mode' must be the first argument?
270 (define (def-rtx-operand-node name-args arg-types arg-modes class action)
271 ; Operand nodes must specify an action.
273 (let ((name (car name-args))
274 (args (cdr name-args)))
275 (let ((rtx (make <rtx-func> name args
279 (eval (list 'lambda (cons '*estate* args) action))
281 ; Add it to the table of rtx handlers.
282 (hashq-set! -rtx-func-table name rtx)
283 (set! -rtx-num-next (+ -rtx-num-next 1))
284 (set! -rtx-name-list (cons name -rtx-name-list))
288 (define define-rtx-operand-node
289 ; Written this way so Hobbit can handle it.
290 (defmacro:syntax-transformer (lambda arg-list
291 (apply def-rtx-operand-node arg-list)
295 ; Convert one rtx expression into another.
296 ; NAME-ARGS is a list of the operation name and arguments.
297 ; ACTION is a list of Scheme expressions to perform the operation.
298 ; The result of ACTION must be another rtx expression (a list).
300 (define (def-rtx-macro-node name-args action)
301 ; macro nodes must specify an action
303 (let ((name (car name-args))
304 (args (cdr name-args)))
305 (let ((rtx (make <rtx-func> name args #f #f
308 (eval (list 'lambda args action))
310 ; Add it to the table of rtx macros.
311 (hashq-set! -rtx-macro-table name rtx)
312 (set! -rtx-num-next (+ -rtx-num-next 1))
313 (set! -rtx-name-list (cons name -rtx-name-list))
317 (define define-rtx-macro-node
318 ; Written this way so Hobbit can handle it.
319 (defmacro:syntax-transformer (lambda arg-list
320 (apply def-rtx-macro-node arg-list)
324 ; RTL macro expansion.
325 ; RTL macros are different than pmacros. The difference is that the expansion
326 ; happens internally, RTL macros are part of the language.
328 ; Lookup MACRO-NAME and return its <rtx-func> object or #f if not found.
330 (define (-rtx-macro-lookup macro-name)
331 (hashq-ref -rtx-macro-table macro-name)
334 ; Lookup (car exp) and return the macro's lambda if it is one or #f.
336 (define (-rtx-macro-check exp fn-getter)
337 (let ((macro (hashq-ref -rtx-macro-table (car exp))))
345 (define (-rtx-macro-expand-list exp fn-getter)
346 (let ((macro (-rtx-macro-check exp fn-getter)))
348 (apply macro (map (lambda (x) (-rtx-macro-expand x fn-getter))
350 (map (lambda (x) (-rtx-macro-expand x fn-getter))
354 ; Main entry point to expand a macro invocation.
356 (define (-rtx-macro-expand exp fn-getter)
357 (if (pair? exp) ; pair? -> cheap (and (not (null? exp)) (list? exp))
358 (let ((result (-rtx-macro-expand-list exp fn-getter)))
359 ; If the result is a new macro invocation, recurse.
361 (let ((macro (-rtx-macro-check result fn-getter)))
363 (-rtx-macro-expand (apply macro (cdr result)) fn-getter)
369 ; Publically accessible version.
371 (define rtx-macro-expand -rtx-macro-expand)
373 ; RTX canonicalization.
376 ; Subroutine of rtx-canonicalize.
377 ; Return canonical form of rtx expression EXPR.
378 ; CONTEXT is a <context> object or #f if there is none.
379 ; It is used for error message.
380 ; RTX-OBJ is the <rtx-func> object of (car expr).
382 (define (-rtx-canonicalize-expr context rtx-obj expr)
386 ; Return canonical form of EXPR.
387 ; CONTEXT is a <context> object or #f if there is none.
388 ; It is used for error message.
391 ; - operand shortcuts expanded
392 ; - numbers -> (const number)
393 ; - operand-name -> (operand operand-name)
394 ; - ifield-name -> (ifield ifield-name)
395 ; - no options -> null option list
396 ; - absent result mode of those that require a mode -> DFLT
397 ; - rtx macros are expanded
399 ; EXPR is returned in source form. We could speed up future processing by
400 ; transforming it into a more compiled form, but that makes debugging more
401 ; difficult, so for now we don't.
403 (define (rtx-canonicalize context expr)
405 (cond ((integer? expr)
406 (rtx-make-const 'INT expr))
408 (let ((op (current-op-lookup expr)))
410 (rtx-make-operand expr)
411 (context-error context "can't canonicalize" expr))))
415 (context-error context "can't canonicalize" expr)))
420 ; Get implied mode of X, either an operand expression, sequence temp, or
421 ; a hardware reference expression.
422 ; The result is the name of the mode.
424 (define (rtx-lvalue-mode-name estate x)
427 ; ((operand) (obj:name (op:mode (current-op-lookup (cadr x)))))
428 ((xop) (obj:name (send (rtx-xop-obj x) 'get-mode)))
430 ; (if (eq? (rtx-opspec-mode x) 'VOID)
431 ; (rtx-lvalue-mode-name estate (rtx-opspec-hw-ref x))
432 ; (rtx-opspec-mode x)))
433 ; ((reg mem) (cadr x))
434 ; ((local) (obj:name (rtx-temp-mode (rtx-temp-lookup (estate-env estate)
437 (error "rtx-lvalue-mode-name: not an operand or hardware reference:" x)))
440 ; Lookup the mode to use for semantic operations (unsigned modes aren't
441 ; allowed since we don't have ANDUSI, etc.).
442 ; ??? I have actually implemented both ways (full use of unsigned modes
443 ; and mostly hidden use of unsigned modes). Neither makes me real
444 ; comfortable, though I liked bringing unsigned modes out into the open
445 ; even if it doubled the number of semantic operations.
447 (define (-rtx-sem-mode m) (or (mode:sem-mode m) m))
449 ; MODE is a mode name or <mode> object.
450 (define (-rtx-lazy-sem-mode mode) (-rtx-sem-mode (mode:lookup mode)))
452 ; Return the mode of object OBJ.
454 (define (-rtx-obj-mode obj) (send obj 'get-mode))
456 ; Return a boolean indicating of modes M1,M2 are compatible.
458 (define (-rtx-mode-compatible? m1 m2)
459 (let ((mode1 (-rtx-lazy-sem-mode m1))
460 (mode2 (-rtx-lazy-sem-mode m2)))
461 ;(eq? (obj:name mode1) (obj:name mode2)))
462 ; ??? This is more permissive than is perhaps proper.
463 (mode-compatible? 'sameclass mode1 mode2))
466 ; Environments (sequences with local variables).
468 ; Temporaries are created within a sequence.
469 ; e.g. (sequence ((WI tmp)) (set tmp reg0) ...)
470 ; ??? Perhaps what we want here is `let' but for now I prefer `sequence'.
471 ; This isn't exactly `let' either as no initial value is specified.
472 ; Environments are also used to specify incoming values from the top level.
474 (define <rtx-temp> (class-make '<rtx-temp> nil '(name mode value) nil))
476 ;(define cx-temp:name (elm-make-getter <c-expr-temp> 'name))
477 ;(define cx-temp:mode (elm-make-getter <c-expr-temp> 'mode))
478 ;(define cx-temp:value (elm-make-getter <c-expr-temp> 'value))
480 (define-getters <rtx-temp> rtx-temp (name mode value))
484 (lambda (self name mode value)
485 (elm-set! self 'name name)
486 (elm-set! self 'mode mode)
487 (elm-set! self 'value (if value value (gen-temp name)))
491 (define (gen-temp name)
492 ; ??? calls to gen-c-symbol don't belong here
493 (string-append "tmp_" (gen-c-symbol name))
496 ; Return a boolean indicating if X is an <rtx-temp>.
498 (define (rtx-temp? x) (class-instance? <rtx-temp> x))
500 ; Respond to 'get-mode messages.
502 (method-make! <rtx-temp> 'get-mode (lambda (self) (elm-get self 'mode)))
504 ; Respond to 'get-name messages.
506 (method-make! <rtx-temp> 'get-name (lambda (self) (elm-get self 'name)))
508 ; An environment is a list of <rtx-temp> objects.
509 ; An environment stack is a list of environments.
511 (define (rtx-env-stack-empty? env-stack) (null? env-stack))
512 (define (rtx-env-stack-head env-stack) (car env-stack))
513 (define (rtx-env-var-list env) env)
514 (define (rtx-env-empty-stack) nil)
515 (define (rtx-env-init-stack1 vars-alist)
516 (if (null? vars-alist)
518 (cons (rtx-env-make vars-alist) nil))
520 (define (rtx-env-empty? env) (null? env))
522 ; Create an initial environment.
523 ; VAR-LIST is a list of (name <mode> value) elements.
525 (define (rtx-env-make var-list)
526 ; Convert VAR-LIST to an associative list of <rtx-temp> objects.
527 (map (lambda (var-spec)
530 (car var-spec) (cadr var-spec) (caddr var-spec))))
534 ; Create an initial environment with local variables.
535 ; VAR-LIST is a list of (mode-name name) elements (the argument to `sequence').
537 (define (rtx-env-make-locals var-list)
538 ; Convert VAR-LIST to an associative list of <rtx-temp> objects.
539 (map (lambda (var-spec)
540 (cons (cadr var-spec)
542 (cadr var-spec) (mode:lookup (car var-spec)) #f)))
546 ; Push environment ENV onto the front of environment stack ENV-STACK,
547 ; returning a new object. ENV-STACK is not modified.
549 (define (rtx-env-push env-stack env)
553 (define (rtx-temp-lookup env name)
554 ;(display "looking up:") (display name) (newline)
555 (let loop ((stack (rtx-env-var-list env)))
558 (let ((temp (assq-ref (car stack) name)))
561 (loop (cdr stack))))))
564 ; Create a "closure" of EXPR using the current temp stack.
566 (define (-rtx-closure-make estate expr)
567 (rtx-make 'closure expr (estate-env estate))
570 (define (rtx-env-dump env)
572 (if (rtx-env-stack-empty? stack)
573 (display "rtx-env stack (empty):\n")
574 (let loop ((stack stack) (level 0))
578 (display "rtx-env stack, level ")
581 (for-each (lambda (var)
583 ;(display (obj:name (rtx-temp-mode (cdr var))))
585 (display (rtx-temp-name (cdr var)))
588 (loop (cdr stack) (+ level 1)))))))
591 ; Build, test, and analyze various kinds of rtx's.
592 ; ??? A lot of this could be machine generated except that I don't yet need
595 (define (rtx-make kind . args)
596 (cons kind (-rtx-munge-mode&options args))
599 (define rtx-name car)
600 (define (rtx-kind? kind rtx) (eq? kind (rtx-name rtx)))
602 (define (rtx-make-const mode value) (rtx-make 'const mode value))
603 (define (rtx-make-enum mode value) (rtx-make 'enum mode value))
605 (define (rtx-constant? rtx) (memq (rtx-name rtx) '(const enum)))
607 ; Return value of constant RTX (either const or enum).
608 (define (rtx-constant-value rtx)
610 ((const) (rtx-const-value rtx))
611 ((enum) (enum-lookup-val (rtx-enum-value rtx)))
612 (else (error "rtx-constant-value: not const or enum" rtx)))
615 (define rtx-options cadr)
616 (define rtx-mode caddr)
617 (define rtx-args cdddr)
618 (define rtx-arg1 cadddr)
619 (define (rtx-arg2 rtx) (car (cddddr rtx)))
621 (define rtx-const-value rtx-arg1)
622 (define rtx-enum-value rtx-arg1)
624 (define rtx-reg-name rtx-arg1)
626 ; Return register number or #f if absent.
627 ; (reg options mode hw-name [regno [selector]])
628 (define (rtx-reg-number rtx) (list-maybe-ref rtx 4))
630 ; Return register selector or #f if absent.
631 (define (rtx-reg-selector rtx) (list-maybe-ref rtx 5))
633 ; Return both register number and selector.
634 (define rtx-reg-index-sel cddddr)
636 ; Return memory address.
637 (define rtx-mem-addr rtx-arg1)
639 ; Return memory selector or #f if absent.
640 (define (rtx-mem-sel mem) (list-maybe-ref mem 4))
642 ; Return both memory address and selector.
643 (define rtx-mem-index-sel cdddr)
645 ; Return MEM with new address NEW-ADDR.
646 ; ??? Complicate as necessary.
647 (define (rtx-change-address mem new-addr)
655 ; Return argument to `symbol' rtx.
656 (define rtx-symbol-name rtx-arg1)
658 (define (rtx-make-ifield ifield-name) (rtx-make 'ifield ifield-name))
659 (define (rtx-ifield? rtx) (eq? 'ifield (rtx-name rtx)))
660 (define (rtx-ifield-name rtx)
661 (let ((ifield (rtx-arg1 rtx)))
666 (define (rtx-ifield-obj rtx)
667 (let ((ifield (rtx-arg1 rtx)))
669 (current-ifield-lookup ifield)
673 (define (rtx-make-operand op-name) (rtx-make 'operand op-name))
674 (define (rtx-operand? rtx) (eq? 'operand (rtx-name rtx)))
675 (define (rtx-operand-name rtx)
676 (let ((operand (rtx-arg1 rtx)))
677 (if (symbol? operand)
681 (define (rtx-operand-obj rtx)
682 (let ((operand (rtx-arg1 rtx)))
683 (if (symbol? operand)
684 (current-op-lookup operand)
688 (define (rtx-make-local local-name) (rtx-make 'local local-name))
689 (define (rtx-local? rtx) (eq? 'local (rtx-name rtx)))
690 (define (rtx-local-name rtx)
691 (let ((local (rtx-arg1 rtx)))
696 (define (rtx-local-obj rtx)
697 (let ((local (rtx-arg1 rtx)))
699 (error "can't use rtx-local-obj on local name")
703 (define rtx-xop-obj rtx-arg1)
705 ;(define (rtx-opspec? rtx) (eq? 'opspec (rtx-name rtx)))
706 ;(define (rtx-opspec-mode rtx) (rtx-mode rtx))
707 ;(define (rtx-opspec-hw-ref rtx) (list-ref rtx 5))
708 ;(define (rtx-opspec-set-op-num! rtx num) (set-car! (cddddr rtx) num))
710 (define rtx-index-of-value rtx-arg1)
712 (define (rtx-make-set dest src) (rtx-make 'set dest src))
713 (define rtx-set-dest rtx-arg1)
714 (define rtx-set-src rtx-arg2)
715 (define (rtx-single-set? rtx) (eq? (car rtx) 'set))
717 (define rtx-alu-op-mode rtx-mode)
718 (define (rtx-alu-op-arg rtx n) (list-ref rtx (+ n 3)))
720 (define (rtx-boolif-op-arg rtx n) (list-ref rtx (+ n 3)))
722 (define rtx-cmp-op-mode rtx-mode)
723 (define (rtx-cmp-op-arg rtx n) (list-ref rtx (+ n 3)))
725 (define rtx-number-list-values cdddr)
727 (define rtx-member-value rtx-arg1)
728 (define (rtx-member-set rtx) (list-ref rtx 4))
730 (define rtx-if-mode rtx-mode)
731 (define (rtx-if-test rtx) (rtx-arg1 rtx))
732 (define (rtx-if-then rtx) (list-ref rtx 4))
733 ; If `else' clause is missing the result is #f.
734 (define (rtx-if-else rtx) (list-maybe-ref rtx 5))
736 (define (rtx-eq-attr-owner rtx) (list-ref rtx 3))
737 (define (rtx-eq-attr-attr rtx) (list-ref rtx 4))
738 (define (rtx-eq-attr-value rtx) (list-ref rtx 5))
740 (define (rtx-sequence-locals rtx) (cadddr rtx))
741 (define (rtx-sequence-exprs rtx) (cddddr rtx))
743 ; Same as rtx-sequence-locals except return in assq'able form.
745 (define (rtx-sequence-assq-locals rtx)
746 (let ((locals (rtx-sequence-locals rtx)))
748 (list (cadr local) (car local)))
752 ; Return a semi-pretty symbol describing RTX.
753 ; This is used by hw to include the index in the element's name.
755 (define (rtx-pretty-name rtx)
758 ((const) (number->string (rtx-const-value rtx)))
759 ((operand) (obj:name (rtx-operand-obj rtx)))
760 ((local) (rtx-local-name rtx))
761 ((xop) (obj:name (rtx-xop-obj rtx)))
763 (if (null? (cdr rtx))
768 (string-append "-" (rtx-pretty-name elm)))
773 ; RTL expression traversal support.
774 ; Traversal (and compilation) involves validating the source form and
775 ; converting it to internal form.
776 ; ??? At present the internal form is also the source form (easier debugging).
778 ; Set to #t to debug rtx traversal.
780 (define -rtx-traverse-debug? #f)
782 ; Container to record the current state of traversal.
783 ; This is initialized before traversal, and modified (in a copy) as the
784 ; traversal state changes.
785 ; This doesn't record all traversal state, just the more static elements.
786 ; There's no point in recording things like the parent expression and operand
787 ; position as they change for every sub-traversal.
788 ; The main raison d'etre for this class is so we can add more state without
789 ; having to modify all the traversal handlers.
790 ; ??? At present it's not a proper "class" as there's no real need.
792 ; CONTEXT is a <context> object or #f if there is none.
793 ; It is used for error messages.
795 ; EXPR-FN is a dual-purpose beast. The first purpose is to just process
796 ; the current expression and return the result. The second purpose is to
797 ; lookup the function which will then process the expression.
798 ; It is applied recursively to the expression and each sub-expression.
799 ; It must be defined as
800 ; (lambda (rtx-obj expr mode parent-expr op-pos tstate appstuff) ...).
801 ; If the result of EXPR-FN is a lambda, it is applied to
802 ; (cons TSTATE (cdr EXPR)). TSTATE is prepended to the arguments.
803 ; For syntax expressions if the result of EXPR-FN is #f, the operands are
804 ; processed using the builtin traverser.
805 ; So to repeat: EXPR-FN can process the expression, and if its result is a
806 ; lambda then it also processes the expression. The arguments to EXPR-FN
807 ; are (rtx-obj expr mode parent-expr op-pos tstate appstuff). The format
808 ; of the result of EXPR-FN are (cons TSTATE (cdr EXPR)).
809 ; The reason for the duality is that when trying to understand EXPR (e.g. when
810 ; computing the insn format) EXPR-FN processes the expression itself, and
811 ; when evaluating EXPR it's the result of EXPR-FN that computes the value.
813 ; ENV is the current environment. This is a stack of sequence locals.
815 ; COND? is a boolean indicating if the current expression is on a conditional
816 ; execution path. This is for optimization purposes only and it is always ok
817 ; to pass #t, except for the top-level caller which must pass #f (since the top
818 ; level expression obviously isn't subject to any condition).
819 ; It is used, for example, to speed up the simulator: there's no need to keep
820 ; track of whether an operand has been assigned to (or potentially read from)
821 ; if it's known it's always assigned to.
823 ; SET? is a boolean indicating if the current expression is an operand being
826 ; OWNER is the owner of the expression or #f if there is none.
827 ; Typically it is an <insn> object.
829 ; KNOWN is an alist of known values. This is used by rtx-simplify.
830 ; Each element is (name . value) where
831 ; NAME is either an ifield or operand name (in the future it might be a
832 ; sequence local name), and
833 ; VALUE is either (const mode value) or (numlist mode value1 value2 ...).
835 ; DEPTH is the current traversal depth.
837 (define (tstate-make context owner expr-fn env cond? set? known depth)
838 (vector context owner expr-fn env cond? set? known depth)
841 (define (tstate-context state) (vector-ref state 0))
842 (define (tstate-set-context! state newval) (vector-set! state 0 newval))
843 (define (tstate-owner state) (vector-ref state 1))
844 (define (tstate-set-owner! state newval) (vector-set! state 1 newval))
845 (define (tstate-expr-fn state) (vector-ref state 2))
846 (define (tstate-set-expr-fn! state newval) (vector-set! state 2 newval))
847 (define (tstate-env state) (vector-ref state 3))
848 (define (tstate-set-env! state newval) (vector-set! state 3 newval))
849 (define (tstate-cond? state) (vector-ref state 4))
850 (define (tstate-set-cond?! state newval) (vector-set! state 4 newval))
851 (define (tstate-set? state) (vector-ref state 5))
852 (define (tstate-set-set?! state newval) (vector-set! state 5 newval))
853 (define (tstate-known state) (vector-ref state 6))
854 (define (tstate-set-known! state newval) (vector-set! state 6 newval))
855 (define (tstate-depth state) (vector-ref state 7))
856 (define (tstate-set-depth! state newval) (vector-set! state 7 newval))
858 ; Create a copy of STATE.
860 (define (tstate-copy state)
861 ; A fast vector-copy would be nice, but this is simple and portable.
862 (list->vector (vector->list state))
865 ; Create a copy of STATE with a new environment ENV.
867 (define (tstate-new-env state env)
868 (let ((result (tstate-copy state)))
869 (tstate-set-env! result env)
873 ; Create a copy of STATE with environment ENV pushed onto the existing
875 ; There's no routine to pop the environment list as there's no current
876 ; need for it: we make a copy of the state when we push.
878 (define (tstate-push-env state env)
879 (let ((result (tstate-copy state)))
880 (tstate-set-env! result (cons env (tstate-env result)))
884 ; Create a copy of STATE with a new COND? value.
886 (define (tstate-new-cond? state cond?)
887 (let ((result (tstate-copy state)))
888 (tstate-set-cond?! result cond?)
892 ; Create a copy of STATE with a new SET? value.
894 (define (tstate-new-set? state set?)
895 (let ((result (tstate-copy state)))
896 (tstate-set-set?! result set?)
900 ; Lookup NAME in the known value table. Returns the value or #f if not found.
902 (define (tstate-known-lookup tstate name)
903 (let ((known (tstate-known tstate)))
904 (assq-ref known name))
907 ; Increment the recorded traversal depth of TSTATE.
909 (define (tstate-incr-depth! tstate)
910 (tstate-set-depth! tstate (1+ (tstate-depth tstate)))
913 ; Decrement the recorded traversal depth of TSTATE.
915 (define (tstate-decr-depth! tstate)
916 (tstate-set-depth! tstate (1- (tstate-depth tstate)))
919 ; Traversal/compilation support.
921 ; Return a boolean indicating if X is a mode.
923 (define (-rtx-any-mode? x)
924 (->bool (mode:lookup x))
927 ; Return a boolean indicating if X is a symbol or rtx.
929 (define (-rtx-symornum? x)
930 (or (symbol? x) (number? x))
933 ; Traverse a list of rtx's.
935 (define (-rtx-traverse-rtx-list rtx-list mode expr op-num tstate appstuff)
937 ; ??? Shouldn't OP-NUM change for each element?
938 (-rtx-traverse rtx 'RTX mode expr op-num tstate appstuff))
942 ; Cover-fn to context-error for signalling an error during rtx traversal.
944 (define (-rtx-traverse-error tstate errmsg expr op-num)
945 ; (parse-error context (string-append errmsg ", operand number "
946 ; (number->string op-num))
948 (context-error (tstate-context tstate)
949 (string-append errmsg ", operand #" (number->string op-num))
954 ; These are defined as individual functions that are then built into a table
955 ; so that we can use Hobbit's "fastcall" support.
957 ; The result is either a pair of the parsed VAL and new TSTATE,
958 ; or #f meaning there is no change (saves lots of unnecessarying cons'ing).
960 (define (-rtx-traverse-options val mode expr op-num tstate appstuff)
964 (define (-rtx-traverse-anymode val mode expr op-num tstate appstuff)
965 (let ((val-obj (mode:lookup val)))
967 (-rtx-traverse-error tstate "expecting a mode"
972 (define (-rtx-traverse-intmode val mode expr op-num tstate appstuff)
973 (let ((val-obj (mode:lookup val)))
975 (or (memq (mode:class val-obj) '(INT UINT))
978 (-rtx-traverse-error tstate "expecting an integer mode"
982 (define (-rtx-traverse-floatmode val mode expr op-num tstate appstuff)
983 (let ((val-obj (mode:lookup val)))
985 (or (memq (mode:class val-obj) '(FLOAT))
988 (-rtx-traverse-error tstate "expecting a float mode"
992 (define (-rtx-traverse-nummode val mode expr op-num tstate appstuff)
993 (let ((val-obj (mode:lookup val)))
995 (or (memq (mode:class val-obj) '(INT UINT FLOAT))
998 (-rtx-traverse-error tstate "expecting a numeric mode"
1002 (define (-rtx-traverse-explnummode val mode expr op-num tstate appstuff)
1003 (let ((val-obj (mode:lookup val)))
1005 (-rtx-traverse-error tstate "expecting a mode"
1007 (if (memq val '(DFLT VOID))
1008 (-rtx-traverse-error tstate "DFLT and VOID not allowed here"
1013 (define (-rtx-traverse-nonvoidmode val mode expr op-num tstate appstuff)
1015 (-rtx-traverse-error tstate "mode can't be VOID"
1020 (define (-rtx-traverse-voidmode val mode expr op-num tstate appstuff)
1021 (if (memq val '(DFLT VOID))
1023 (-rtx-traverse-error tstate "expecting mode VOID"
1027 (define (-rtx-traverse-dfltmode val mode expr op-num tstate appstuff)
1030 (-rtx-traverse-error tstate "expecting mode DFLT"
1034 (define (-rtx-traverse-rtx val mode expr op-num tstate appstuff)
1035 ; Commented out 'cus it doesn't quite work yet.
1036 ; (if (not (rtx? val))
1037 ; (-rtx-traverse-error tstate "expecting an rtx"
1039 (cons (-rtx-traverse val 'RTX mode expr op-num tstate appstuff)
1043 (define (-rtx-traverse-setrtx val mode expr op-num tstate appstuff)
1044 ; FIXME: Still need to turn it off for sub-exprs.
1045 ; e.g. (mem (reg ...))
1046 ; Commented out 'cus it doesn't quite work yet.
1047 ; (if (not (rtx? val))
1048 ; (-rtx-traverse-error tstate "expecting an rtx"
1050 (cons (-rtx-traverse val 'SETRTX mode expr op-num
1051 (tstate-new-set? tstate #t)
1056 ; This is the test of an `if'.
1058 (define (-rtx-traverse-testrtx val mode expr op-num tstate appstuff)
1059 ; Commented out 'cus it doesn't quite work yet.
1060 ; (if (not (rtx? val))
1061 ; (-rtx-traverse-error tstate "expecting an rtx"
1063 (cons (-rtx-traverse val 'RTX mode expr op-num tstate appstuff)
1066 (not (rtx-compile-time-constant? val))))
1069 (define (-rtx-traverse-condrtx val mode expr op-num tstate appstuff)
1070 (if (not (pair? val))
1071 (-rtx-traverse-error tstate "expecting an expression"
1073 (if (eq? (car val) 'else)
1075 (if (!= (+ op-num 2) (length expr))
1076 (-rtx-traverse-error tstate
1077 "`else' clause not last"
1080 (-rtx-traverse-rtx-list
1081 (cdr val) mode expr op-num
1082 (tstate-new-cond? tstate #t)
1084 (tstate-new-cond? tstate #t)))
1086 ; ??? Entries after the first are conditional.
1087 (-rtx-traverse (car val) 'RTX 'ANY expr op-num tstate appstuff)
1088 (-rtx-traverse-rtx-list
1089 (cdr val) mode expr op-num
1090 (tstate-new-cond? tstate #t)
1092 (tstate-new-cond? tstate #t)))
1095 (define (-rtx-traverse-casertx val mode expr op-num tstate appstuff)
1096 (if (or (not (list? val))
1098 (-rtx-traverse-error tstate
1099 "invalid `case' expression"
1101 ; car is either 'else or list of symbols/numbers
1102 (if (not (or (eq? (car val) 'else)
1103 (and (list? (car val))
1104 (not (null? (car val)))
1105 (all-true? (map -rtx-symornum?
1107 (-rtx-traverse-error tstate
1108 "invalid `case' choice"
1110 (if (and (eq? (car val) 'else)
1111 (!= (+ op-num 2) (length expr)))
1112 (-rtx-traverse-error tstate "`else' clause not last"
1114 (cons (cons (car val)
1115 (-rtx-traverse-rtx-list
1116 (cdr val) mode expr op-num
1117 (tstate-new-cond? tstate #t)
1119 (tstate-new-cond? tstate #t))
1122 (define (-rtx-traverse-locals val mode expr op-num tstate appstuff)
1123 (if (not (list? val))
1124 (-rtx-traverse-error tstate "bad locals list"
1126 (for-each (lambda (var)
1127 (if (or (not (list? var))
1129 (not (-rtx-any-mode? (car var)))
1130 (not (symbol? (cadr var))))
1131 (-rtx-traverse-error tstate
1135 (let ((env (rtx-env-make-locals val)))
1136 (cons val (tstate-push-env tstate env)))
1139 (define (-rtx-traverse-env val mode expr op-num tstate appstuff)
1140 ; VAL is an environment stack.
1141 (if (not (list? val))
1142 (-rtx-traverse-error tstate "environment not a list"
1144 (cons val (tstate-new-env tstate val))
1147 (define (-rtx-traverse-attrs val mode expr op-num tstate appstuff)
1148 ; (cons val ; (atlist-source-form (atlist-parse val "" "with-attr"))
1153 (define (-rtx-traverse-symbol val mode expr op-num tstate appstuff)
1154 (if (not (symbol? val))
1155 (-rtx-traverse-error tstate "expecting a symbol"
1160 (define (-rtx-traverse-string val mode expr op-num tstate appstuff)
1161 (if (not (string? val))
1162 (-rtx-traverse-error tstate "expecting a string"
1167 (define (-rtx-traverse-number val mode expr op-num tstate appstuff)
1168 (if (not (number? val))
1169 (-rtx-traverse-error tstate "expecting a number"
1174 (define (-rtx-traverse-symornum val mode expr op-num tstate appstuff)
1175 (if (not (or (symbol? val) (number? val)))
1176 (-rtx-traverse-error tstate
1177 "expecting a symbol or number"
1182 (define (-rtx-traverse-object val mode expr op-num tstate appstuff)
1186 ; Table of rtx traversers.
1187 ; This is a vector of size rtx-max-num.
1188 ; Each entry is a list of (arg-type-name . traverser) elements
1189 ; for rtx-arg-types.
1191 (define -rtx-traverser-table #f)
1193 ; Return a hash table of standard operand traversers.
1194 ; The result of each traverser is a pair of the compiled form of `val' and
1195 ; a possibly new traversal state or #f if there is no change.
1197 (define (-rtx-make-traverser-table)
1198 (let ((hash-tab (make-hash-table 31))
1201 ; /fastcall-make is recognized by Hobbit and handled specially.
1202 ; When not using Hobbit it is a macro that returns its argument.
1203 (cons 'OPTIONS (/fastcall-make -rtx-traverse-options))
1204 (cons 'ANYMODE (/fastcall-make -rtx-traverse-anymode))
1205 (cons 'INTMODE (/fastcall-make -rtx-traverse-intmode))
1206 (cons 'FLOATMODE (/fastcall-make -rtx-traverse-floatmode))
1207 (cons 'NUMMODE (/fastcall-make -rtx-traverse-nummode))
1208 (cons 'EXPLNUMMODE (/fastcall-make -rtx-traverse-explnummode))
1209 (cons 'NONVOIDFLTODE (/fastcall-make -rtx-traverse-nonvoidmode))
1210 (cons 'VOIDFLTODE (/fastcall-make -rtx-traverse-voidmode))
1211 (cons 'DFLTMODE (/fastcall-make -rtx-traverse-dfltmode))
1212 (cons 'RTX (/fastcall-make -rtx-traverse-rtx))
1213 (cons 'SETRTX (/fastcall-make -rtx-traverse-setrtx))
1214 (cons 'TESTRTX (/fastcall-make -rtx-traverse-testrtx))
1215 (cons 'CONDRTX (/fastcall-make -rtx-traverse-condrtx))
1216 (cons 'CASERTX (/fastcall-make -rtx-traverse-casertx))
1217 (cons 'LOCALS (/fastcall-make -rtx-traverse-locals))
1218 (cons 'ENV (/fastcall-make -rtx-traverse-env))
1219 (cons 'ATTRS (/fastcall-make -rtx-traverse-attrs))
1220 (cons 'SYMBOL (/fastcall-make -rtx-traverse-symbol))
1221 (cons 'STRING (/fastcall-make -rtx-traverse-string))
1222 (cons 'NUMBER (/fastcall-make -rtx-traverse-number))
1223 (cons 'SYMORNUM (/fastcall-make -rtx-traverse-symornum))
1224 (cons 'OBJECT (/fastcall-make -rtx-traverse-object))
1227 (for-each (lambda (traverser)
1228 (hashq-set! hash-tab (car traverser) (cdr traverser)))
1234 ; Traverse the operands of EXPR, a canonicalized RTL expression.
1235 ; Here "canonicalized" means that -rtx-munge-mode&options has been called to
1236 ; insert an option list and mode if they were absent in the original
1239 (define (-rtx-traverse-operands rtx-obj expr tstate appstuff)
1240 (if -rtx-traverse-debug?
1242 (display (spaces (* 4 (tstate-depth tstate))))
1243 (display "Traversing operands of: ")
1244 (display (rtx-dump expr))
1246 (rtx-env-dump (tstate-env tstate))
1250 (let loop ((operands (cdr expr))
1252 (arg-types (vector-ref -rtx-traverser-table (rtx-num rtx-obj)))
1253 (arg-modes (rtx-arg-modes rtx-obj))
1257 (let ((varargs? (and (pair? arg-types) (symbol? (car arg-types)))))
1259 (if -rtx-traverse-debug?
1261 (display (spaces (* 4 (tstate-depth tstate))))
1262 (if (null? operands)
1263 (display "end of operands")
1265 (display "op-num ") (display op-num) (display ": ")
1266 (display (rtx-dump (car operands)))
1268 (display (if varargs? (car arg-types) (caar arg-types)))
1270 (display (if varargs? arg-modes (car arg-modes)))
1276 (cond ((null? operands)
1277 ; Out of operands, check if we have the expected number.
1278 (if (or (null? arg-types)
1281 (context-error (tstate-context tstate)
1282 "missing operands" (rtx-strdump expr))))
1285 (context-error (tstate-context tstate)
1286 "too many operands" (rtx-strdump expr)))
1289 (let ((type (if varargs? arg-types (car arg-types)))
1290 (mode (let ((mode-spec (if varargs?
1293 ; This is small enough that this is fast enough,
1294 ; and the number of entries should be stable.
1299 ((OP0) (rtx-mode expr))
1301 ; If there is an explicit mode, use it.
1302 ; Otherwise we have to look at operand 1.
1303 (if (eq? (rtx-mode expr) 'DFLT)
1307 ; If there is an explicit mode, use it.
1308 ; Otherwise we have to look at operand 2.
1309 (if (eq? (rtx-mode expr) 'DFLT)
1313 (val (car operands))
1316 ; Look up the traverser for this kind of operand and perform it.
1317 (let ((traverser (cdr type)))
1318 (let ((traversed-val (fastcall6 traverser val mode expr op-num tstate appstuff)))
1321 (set! val (car traversed-val))
1322 (set! tstate (cdr traversed-val))))))
1324 ; Done with this operand, proceed to the next.
1325 (loop (cdr operands)
1327 (if varargs? arg-types (cdr arg-types))
1328 (if varargs? arg-modes (cdr arg-modes))
1329 (cons val result)))))))
1332 ; Publically accessible version of -rtx-traverse-operands as EXPR-FN may
1335 (define rtx-traverse-operands -rtx-traverse-operands)
1337 ; Subroutine of -rtx-munge-mode&options.
1338 ; Return boolean indicating if X is an rtx option.
1340 (define (-rtx-option? x)
1342 (char=? (string-ref x 0) #\:))
1345 ; Subroutine of -rtx-munge-mode&options.
1346 ; Return boolean indicating if X is an rtx option list.
1348 (define (-rtx-option-list? x)
1351 (-rtx-option? (car x))))
1354 ; Subroutine of -rtx-traverse-expr to fill in the mode if absent and to
1355 ; collect the options into one list.
1356 ; ARGS is the list of arguments to the rtx function
1357 ; (e.g. (1 2) in (add 1 2)).
1358 ; ??? "munge" is an awkward name to use here, but I like it for now because
1359 ; it's easy to grep for.
1360 ; ??? An empty option list requires a mode to be present so that the empty
1361 ; list in `(sequence () foo bar)' is unambiguously recognized as the locals
1362 ; list. Icky, sure, but less icky than the alternatives thus far.
1364 (define (-rtx-munge-mode&options args)
1367 ; Pick off the option list if present.
1368 (if (and (pair? args)
1369 (-rtx-option-list? (car args))
1370 ; Handle `(sequence () foo bar)'. If empty list isn't followed
1371 ; by a mode, it is not an option list.
1372 (or (not (null? (car args)))
1373 (and (pair? (cdr args))
1374 (mode-name? (cadr args)))))
1376 (set! options (car args))
1377 (set! args (cdr args))))
1378 ; Pick off the mode if present.
1379 (if (and (pair? args)
1380 (mode-name? (car args)))
1382 (set! mode-name (car args))
1383 (set! args (cdr args))))
1384 ; Now put option list and mode back.
1385 (cons options (cons mode-name args)))
1388 ; Traverse an expression.
1389 ; For syntax expressions arguments are not pre-evaluated before calling the
1390 ; user's expression handler. Otherwise they are.
1391 ; If EXPR-FN wants to just scan the operands, rather than evaluating them,
1392 ; one thing it can do is call back to rtx-traverse-operands.
1393 ; If EXPR-FN returns #f, traverse the operands normally and return
1394 ; (rtx's-name traversed-operand1 ...).
1395 ; This is for semantic-compile's sake and all traversal handlers are
1396 ; required to do this if EXPR-FN returns #f.
1398 (define (-rtx-traverse-expr rtx-obj expr mode parent-expr op-pos tstate appstuff)
1399 (let* ((expr2 (cons (car expr)
1400 (-rtx-munge-mode&options (cdr expr))))
1401 (fn (fastcall7 (tstate-expr-fn tstate)
1402 rtx-obj expr2 mode parent-expr op-pos tstate appstuff)))
1405 ; Don't traverse operands for syntax expressions.
1406 (if (rtx-style-syntax? rtx-obj)
1407 (apply fn (cons tstate (cdr expr2)))
1408 (let ((operands (-rtx-traverse-operands rtx-obj expr2 tstate appstuff)))
1409 (apply fn (cons tstate operands))))
1411 (let ((operands (-rtx-traverse-operands rtx-obj expr2 tstate appstuff)))
1412 (cons (car expr2) operands))))
1415 ; Main entry point for expression traversal.
1416 ; (Actually rtx-traverse is, but it's just a cover function for this.)
1418 ; The result is the result of the lambda EXPR-FN looks up in the case of
1419 ; expressions or an operand object (usually <operand>) in the case of operands.
1421 ; EXPR is the expression to be traversed.
1423 ; MODE is the name of the mode of EXPR.
1425 ; PARENT-EXPR is the expression EXPR is contained in. The top-level
1426 ; caller must pass #f for it.
1428 ; OP-POS is the position EXPR appears in PARENT-EXPR. The
1429 ; top-level caller must pass 0 for it.
1431 ; EXPECTED is one of `-rtx-valid-types' and indicates the expected rtx type
1432 ; or #f if it doesn't matter.
1434 ; TSTATE is the current traversal state.
1436 ; APPSTUFF is for application specific use.
1438 ; All macros are expanded here. User code never sees them.
1439 ; All operand shortcuts are also expand here. User code never sees them.
1441 ; - operands, ifields, and numbers appearing where an rtx is expected are
1442 ; converted to use `operand', `ifield', or `const'.
1444 (define (-rtx-traverse expr expected mode parent-expr op-pos tstate appstuff)
1445 (if -rtx-traverse-debug?
1447 (display (spaces (* 4 (tstate-depth tstate))))
1448 (display "Traversing expr: ")
1451 (display (spaces (* 4 (tstate-depth tstate))))
1452 (display "-expected: ")
1455 (display (spaces (* 4 (tstate-depth tstate))))
1462 (if (pair? expr) ; pair? -> cheap non-null-list?
1464 (let ((rtx-obj (rtx-lookup (car expr))))
1465 (tstate-incr-depth! tstate)
1468 (-rtx-traverse-expr rtx-obj expr mode parent-expr op-pos tstate appstuff)
1469 (let ((rtx-obj (-rtx-macro-lookup (car expr))))
1471 (-rtx-traverse (-rtx-macro-expand expr rtx-evaluator)
1472 expected mode parent-expr op-pos tstate appstuff)
1473 (context-error (tstate-context tstate) "unknown rtx function"
1475 (tstate-decr-depth! tstate)
1478 ; EXPR is not a list.
1479 ; See if it's an operand shortcut.
1480 (if (memq expected '(RTX SETRTX))
1482 (cond ((symbol? expr)
1483 (cond ((current-op-lookup expr)
1485 (rtx-make-operand expr) ; (current-op-lookup expr))
1486 expected mode parent-expr op-pos tstate appstuff))
1487 ((rtx-temp-lookup (tstate-env tstate) expr)
1489 (rtx-make-local expr) ; (rtx-temp-lookup (tstate-env tstate) expr))
1490 expected mode parent-expr op-pos tstate appstuff))
1491 ((current-ifld-lookup expr)
1493 (rtx-make-ifield expr)
1494 expected mode parent-expr op-pos tstate appstuff))
1495 ((enum-lookup-val expr)
1497 (rtx-make-enum 'INT expr)
1498 expected mode parent-expr op-pos tstate appstuff))
1500 (context-error (tstate-context tstate)
1501 "unknown operand" expr))))
1503 (-rtx-traverse (rtx-make-const 'INT expr)
1504 expected mode parent-expr op-pos tstate appstuff))
1506 (context-error (tstate-context tstate)
1507 "unexpected operand"
1510 ; Not expecting RTX or SETRTX.
1511 (context-error (tstate-context tstate)
1512 "unexpected operand"
1516 ; User visible procedures to traverse an rtl expression.
1517 ; These calls -rtx-traverse to do most of the work.
1518 ; See tstate-make for an explanation of EXPR-FN.
1519 ; CONTEXT is a <context> object or #f if there is none.
1520 ; LOCALS is a list of (mode . name) elements (the locals arg to `sequence').
1521 ; APPSTUFF is for application specific use.
1523 (define (rtx-traverse context owner expr expr-fn appstuff)
1524 (-rtx-traverse expr #f 'DFLT #f 0
1525 (tstate-make context owner expr-fn (rtx-env-empty-stack)
1530 (define (rtx-traverse-with-locals context owner expr expr-fn locals appstuff)
1531 (-rtx-traverse expr #f 'DFLT #f 0
1532 (tstate-make context owner expr-fn
1533 (rtx-env-push (rtx-env-empty-stack)
1534 (rtx-env-make-locals locals))
1539 ; Traverser debugger.
1541 (define (rtx-traverse-debug expr)
1544 (lambda (rtx-obj expr mode parent-expr op-pos tstate appstuff)
1546 (display (string-append "rtx=" (obj:name rtx-obj)))
1551 (display " parent=")
1552 (display parent-expr)
1553 (display " op-pos=")
1556 (display (tstate-cond? tstate))
1563 ; Convert rtl expression EXPR from source form to compiled form.
1564 ; The expression is validated and rtx macros are expanded as well.
1565 ; CONTEXT is a <context> object or #f if there is none.
1566 ; It is used in error messages.
1567 ; EXTRA-VARS-ALIST is an association list of extra (symbol <mode> value)
1568 ; elements to be used during value lookup.
1570 ; This does the same operation that rtx-traverse does, except that it provides
1571 ; a standard value for EXPR-FN.
1573 ; ??? In the future the compiled form may be the same as the source form
1574 ; except that all elements would be converted to their respective objects.
1576 (define (-compile-expr-fn rtx-obj expr mode parent-expr op-pos tstate appstuff)
1578 ; The intent of this is to handle sequences/closures, but is it needed?
1579 ; ((rtx-style-syntax? rtx-obj)
1580 ; ((rtx-evaluator rtx-obj) rtx-obj expr mode
1581 ; parent-expr op-pos tstate))
1583 (cons (car expr) ; rtx-obj
1584 (-rtx-traverse-operands rtx-obj expr tstate appstuff))
1587 (define (rtx-compile context expr extra-vars-alist)
1588 (-rtx-traverse expr #f 'DFLT #f 0
1589 (tstate-make context #f
1590 (/fastcall-make -compile-expr-fn)
1591 (rtx-env-init-stack1 extra-vars-alist)
1596 ; Various rtx utilities.
1598 ; Dump an rtx expression.
1600 (define (rtx-dump rtx)
1601 (cond ((list? rtx) (map rtx-dump rtx))
1602 ((object? rtx) (string-append "#<object "
1603 (object-class-name rtx)
1610 ; Dump an expression to a string.
1612 (define (rtx-strdump rtx)
1613 (with-output-to-string
1615 (display (rtx-dump rtx))))
1618 ; Return a boolean indicating if EXPR is known to be a compile-time constant.
1620 (define (rtx-compile-time-constant? expr)
1625 ((memq expr '(FALSE TRUE)) #t)
1629 ; Return boolean indicating if EXPR has side-effects.
1630 ; FIXME: for now punt.
1632 (define (rtx-side-effects? expr)
1636 ; Return a boolean indicating if EXPR is a "true" boolean value.
1638 ; ??? In RTL, #t is a synonym for (const 1). This is confusing for Schemers,
1639 ; so maybe RTL's #t should be renamed to TRUE.
1641 (define (rtx-true? expr)
1644 ((const enum) (!= (rtx-constant-value expr) 0))
1646 ((eq? expr 'TRUE) #t)
1650 ; Return a boolean indicating if EXPR is a "false" boolean value.
1652 ; ??? In RTL, #f is a synonym for (const 0). This is confusing for Schemers,
1653 ; so maybe RTL's #f should be renamed to FALSE.
1655 (define (rtx-false? expr)
1658 ((const enum) (= (rtx-constant-value expr) 0))
1660 ((eq? expr 'FALSE) #t)
1664 ; Return canonical boolean values.
1666 (define (rtx-false) (rtx-make-const 'BI 0))
1667 (define (rtx-true) (rtx-make-const 'BI 1))
1669 ; Convert EXPR to a canonical boolean if possible.
1671 (define (rtx-canonical-bool expr)
1672 (cond ((rtx-side-effects? expr) expr)
1673 ((rtx-false? expr) (rtx-false))
1674 ((rtx-true? expr) (rtx-true))
1678 ; Return rtx values for #f/#t.
1680 (define (rtx-make-bool value)
1686 ; Return #t if X is an rtl expression.
1687 ; e.g. '(add WI dr simm8);
1691 (and (pair? x) ; pair? -> cheap non-null-list?
1692 (or (hashq-ref -rtx-func-table (car x))
1693 (hashq-ref -rtx-macro-table (car x)))))
1696 ; RTL evaluation state.
1697 ; Applications may subclass <eval-state> if they need to add things.
1699 ; This is initialized before evaluation, and modified (in a copy) as the
1700 ; evaluation state changes.
1701 ; This doesn't record all evaluation state, just the less dynamic elements.
1702 ; There's no point in recording things like the parent expression and operand
1703 ; position as they change for every sub-eval.
1704 ; The main raison d'etre for this class is so we can add more state without
1705 ; having to modify all the eval handlers.
1707 (define <eval-state>
1708 (class-make '<eval-state> nil
1710 ; <context> object or #f if there is none
1713 ; Current object rtl is being evaluated for.
1714 ; We need to be able to access the current instruction while
1715 ; generating semantic code. However, the semantic description
1716 ; doesn't specify it as an argument to anything (and we don't
1717 ; want it to). So we record the value here.
1720 ; EXPR-FN is a dual-purpose beast. The first purpose is to
1721 ; just process the current expression and return the result.
1722 ; The second purpose is to lookup the function which will then
1723 ; process the expression. It is applied recursively to the
1724 ; expression and each sub-expression. It must be defined as
1725 ; (lambda (rtx-obj expr mode estate) ...).
1726 ; If the result of EXPR-FN is a lambda, it is applied to
1727 ; (cons ESTATE (cdr EXPR)). ESTATE is prepended to the
1729 ; For syntax expressions if the result of EXPR-FN is #f,
1730 ; the operands are processed using the builtin evaluator.
1731 ; FIXME: This special handling of syntax expressions is
1732 ; not currently done.
1733 ; So to repeat: EXPR-FN can process the expression, and if its
1734 ; result is a lambda then it also processes the expression.
1735 ; The arguments to EXPR-FN are
1736 ; (rtx-obj expr mode estate).
1737 ; The arguments to the result of EXPR-FN are
1738 ; (cons ESTATE (cdr EXPR)).
1739 ; The reason for the duality is mostly history.
1740 ; In time things should be simplified.
1743 ; Current environment. This is a stack of sequence locals.
1746 ; Current evaluation depth. This is used, for example, to
1747 ; control indentation in generated output.
1750 ; Associative list of modifiers.
1751 ; This is here to support things like `delay'.
1757 ; Create an <eval-state> object using a list of keyword/value elements.
1758 ; ARGS is a list of #:keyword/value elements.
1759 ; The result is a list of the unrecognized elements.
1760 ; Subclasses should override this method and send-next it first, then
1761 ; see if they recognize anything in the result, returning what isn't
1765 <eval-state> 'vmake!
1767 (let loop ((args args) (unrecognized nil))
1769 (reverse! unrecognized) ; ??? Could invoke method to initialize here.
1773 (elm-set! self 'context (cadr args)))
1775 (elm-set! self 'owner (cadr args)))
1777 (elm-set! self 'expr-fn (cadr args)))
1779 (elm-set! self 'env (cadr args)))
1781 (elm-set! self 'depth (cadr args)))
1783 (elm-set! self 'modifiers (cadr args)))
1785 ; Build in reverse order, as we reverse it back when we're done.
1787 (cons (cadr args) (cons (car args) unrecognized)))))
1788 (loop (cddr args) unrecognized)))))
1793 (define-getters <eval-state> estate
1794 (context owner expr-fn env depth modifiers)
1796 (define-setters <eval-state> estate
1797 (context owner expr-fn env depth modifiers)
1800 ; Build an estate for use in producing a value from rtl.
1801 ; CONTEXT is a <context> object or #f if there is none.
1802 ; OWNER is the owner of the expression or #f if there is none.
1804 (define (estate-make-for-eval context owner)
1808 #:expr-fn (lambda (rtx-obj expr mode estate)
1809 (rtx-evaluator rtx-obj)))
1812 ; Create a copy of ESTATE.
1814 (define (estate-copy estate)
1815 (object-copy-top estate)
1818 ; Create a copy of STATE with a new environment ENV.
1820 (define (estate-new-env state env)
1821 (let ((result (estate-copy state)))
1822 (estate-set-env! result env)
1826 ; Create a copy of STATE with environment ENV pushed onto the existing
1828 ; There's no routine to pop the environment list as there's no current
1829 ; need for it: we make a copy of the state when we push.
1831 (define (estate-push-env state env)
1832 (let ((result (estate-copy state)))
1833 (estate-set-env! result (cons env (estate-env result)))
1837 ; Create a copy of STATE with modifiers MODS.
1839 (define (estate-with-modifiers state mods)
1840 (let ((result (estate-copy state)))
1841 (estate-set-modifiers! result (append mods (estate-modifiers result)))
1845 ; Convert a tstate to an estate.
1847 (define (tstate->estate t)
1849 #:context (tstate-context t)
1850 #:env (tstate-env t))
1853 ; RTL expression evaluation.
1855 ; ??? These used eval2 at one point. Not sure which is faster but I suspect
1856 ; eval2 is by far. On the otherhand this has yet to be compiled. And this way
1857 ; is more portable, more flexible, and works with guile 1.2 (which has
1858 ; problems with eval'ing self referential vectors, though that's one reason to
1861 ; Set to #t to debug rtx evaluation.
1863 (define -rtx-eval-debug? #f)
1865 ; RTX expression evaluator.
1867 ; EXPR is the expression to be eval'd. It must be in compiled form.
1868 ; MODE is the mode of EXPR, a <mode> object or its name.
1869 ; ESTATE is the current evaluation state.
1871 (define (rtx-eval-with-estate expr mode estate)
1872 (if -rtx-eval-debug?
1874 (display "Traversing ")
1877 (rtx-env-dump (estate-env estate))
1880 (if (pair? expr) ; pair? -> cheap non-null-list?
1882 (let* ((rtx-obj (rtx-lookup (car expr)))
1883 (fn ((estate-expr-fn estate) rtx-obj expr mode estate)))
1886 (apply fn (cons estate (cdr expr)))
1887 ; ; Don't eval operands for syntax expressions.
1888 ; (if (rtx-style-syntax? rtx-obj)
1889 ; (apply fn (cons estate (cdr expr)))
1891 ; (-rtx-eval-operands rtx-obj expr estate)))
1892 ; (apply fn (cons estate operands))))
1894 ; Leave expr unchanged.
1897 ; (-rtx-traverse-operands rtx-obj expr estate)))
1898 ; (cons rtx-obj operands))))
1900 ; EXPR is not a list
1901 (error "argument to rtx-eval-with-estate is not a list" expr))
1904 ; Evaluate rtx expression EXPR and return the computed value.
1905 ; EXPR must already be in compiled form (the result of rtx-compile).
1906 ; OWNER is the owner of the value, used for attribute computation,
1907 ; or #f if there isn't one.
1910 (define (rtx-value expr owner)
1911 (rtx-eval-with-estate expr 'DFLT (estate-make-for-eval #f owner))
1914 ; Instruction field support.
1916 ; Return list of ifield names refered to in EXPR.
1917 ; Assumes EXPR is more than just (ifield x).
1919 (define (rtl-find-ifields expr)
1920 (let ((ifields nil))
1921 (letrec ((scan! (lambda (arg-list)
1922 (for-each (lambda (arg)
1924 (if (eq? (car arg) 'ifield)
1926 (cons (rtx-ifield-name arg)
1928 (scan! (cdr arg)))))
1931 (nub ifields identity)))
1934 ; Hardware rtx handlers.
1936 ; Subroutine of hw to compute the object's name.
1937 ; The name of the operand must include the index so that multiple copies
1938 ; of a hardware object (e.g. h-gr[0], h-gr[14]) can be distinguished.
1939 ; We make some attempt to make the name pretty as it appears in generated
1942 (define (-rtx-hw-name hw hw-name index-arg)
1943 (cond ((hw-scalar? hw)
1946 (symbol-append hw-name '- (rtx-pretty-name index-arg)))
1948 (symbol-append hw-name ; (obj:name (op:type self))
1950 ; (obj:name (op:index self)))))
1951 (stringize index-arg "-"))))
1954 ; Return the <operand> object described by
1955 ; HW-NAME/MODE-NAME/SELECTOR/INDEX-ARG.
1957 ; HW-NAME is the name of the hardware element.
1958 ; INDEX-ARG is an rtx or number of the index.
1959 ; In the case of scalar hardware elements, pass 0 for INDEX-ARG.
1960 ; MODE-NAME is the name of the mode.
1961 ; In the case of a vector of registers, INDEX-ARG is the vector index.
1962 ; In the case of a scalar register, the value is ignored, but pass 0 (??? #f?).
1963 ; SELECTOR is an rtx or number and is passed to HW-NAME to allow selection of a
1964 ; particular variant of the hardware. It's kind of like an INDEX, but along
1965 ; an atypical axis. An example is memory ASI's on Sparc. Pass
1966 ; hw-selector-default if there is no selector.
1967 ; ESTATE is the current rtx evaluation state.
1969 ; e.g. (hw estate WI h-gr #f (const INT 14))
1970 ; selects register 14 of the h-gr set of registers.
1972 ; *** The index is passed unevaluated because for parallel execution support
1973 ; *** a variable is created with a name based on the hardware element and
1974 ; *** index, and we want a reasonably simple and stable name. We get this by
1975 ; *** stringize-ing it.
1976 ; *** ??? Though this needs to be redone anyway.
1978 ; ??? The specified hardware element must be either a scalar or a vector.
1979 ; Maybe in the future allow arrays although there's significant utility in
1980 ; allowing only at most a scalar index.
1982 (define (hw estate mode-name hw-name index-arg selector)
1983 ; Enforce some rules to keep things in line with the current design.
1984 (if (not (symbol? mode-name))
1985 (parse-error "hw" "invalid mode name" mode-name))
1986 (if (not (symbol? hw-name))
1987 (parse-error "hw" "invalid hw name" hw-name))
1988 (if (not (or (number? index-arg)
1990 (parse-error "hw" "invalid index" index-arg))
1991 (if (not (or (number? selector)
1993 (parse-error "hw" "invalid selector" selector))
1995 (let ((hw (current-hw-sem-lookup-1 hw-name)))
1997 (parse-error "hw" "invalid hardware element" hw-name))
1999 (let ((mode (if (eq? mode-name 'DFLT) (hw-mode hw) (mode:lookup mode-name)))
2000 (result (new <operand>))) ; ??? lookup-for-new?
2003 (parse-error "hw" "invalid mode" mode-name))
2005 ; Record the selector.
2006 (elm-xset! result 'selector selector)
2008 ; Create the index object.
2009 (elm-xset! result 'index
2010 (cond ((number? index-arg)
2011 (make <hw-index> 'anonymous 'constant UINT index-arg))
2013 ; For the simulator the following could be done which
2014 ; would save having to create a closure.
2015 ; ??? Old code, left in for now.
2016 ; (rtx-get estate DFLT
2017 ; (rtx-eval (estate-context estate)
2018 ; (estate-econfig estate)
2019 ; index-arg rtx-evaluator))
2020 ; Make sure constant indices are recorded as such.
2021 (if (rtx-constant? index-arg)
2022 (make <hw-index> 'anonymous 'constant UINT
2023 (rtx-constant-value index-arg))
2024 (make <hw-index> 'anonymous 'rtx DFLT
2025 (-rtx-closure-make estate index-arg))))
2026 (else (parse-error "hw" "invalid index" index-arg))))
2028 (if (not (hw-mode-ok? hw (obj:name mode) (elm-xget result 'index)))
2029 (parse-error "hw" "invalid mode for hardware" mode-name))
2031 (elm-xset! result 'type hw)
2032 (elm-xset! result 'mode mode)
2034 (op:set-pretty-sem-name! result hw-name)
2036 ; The name of the operand must include the index so that multiple copies
2037 ; of a hardware object (e.g. h-gr[0], h-gr[14]) can be distinguished.
2038 (let ((name (-rtx-hw-name hw hw-name index-arg)))
2039 (send result 'set-name! name)
2040 (op:set-sem-name! result name))
2042 ; Empty comment and attribute.
2043 ; ??? Stick the arguments in the comment for debugging purposes?
2044 (send result 'set-comment! "")
2045 (send result 'set-atlist! atlist-empty)
2050 ; This is shorthand for (hw estate mode hw-name regno selector).
2051 ; ESTATE is the current rtx evaluation state.
2052 ; INDX-SEL is an optional register number and possible selector.
2053 ; The register number, if present, is (car indx-sel) and must be a number or
2054 ; unevaluated RTX expression.
2055 ; The selector, if present, is (cadr indx-sel) and must be a number or
2056 ; unevaluated RTX expression.
2057 ; ??? A register selector isn't supported yet. It's just an idea that's
2058 ; been put down on paper for future reference.
2060 (define (reg estate mode hw-name . indx-sel)
2061 (s-hw estate mode hw-name
2062 (if (pair? indx-sel) (car indx-sel) 0)
2063 (if (and (pair? indx-sel) (pair? (cdr indx-sel)))
2065 hw-selector-default))
2068 ; This is shorthand for (hw estate mode h-memory addr selector).
2069 ; ADDR must be an unevaluated RTX expression.
2070 ; If present (car sel) must be a number or unevaluated RTX expression.
2072 (define (mem estate mode addr . sel)
2073 (s-hw estate mode 'h-memory addr
2074 (if (pair? sel) (car sel) hw-selector-default))
2077 ; For the rtx nodes to use.
2081 ; The program counter.
2082 ; When this code is loaded, global `pc' is nil, it hasn't been set to the
2083 ; pc operand yet (see operand-init!). We can't use `pc' inside the drn as the
2084 ; value is itself. So we use s-pc. rtl-finish! must be called after
2089 ; Conditional execution.
2091 ; `if' in RTL has a result, like ?: in C.
2092 ; We support both: one with a result (non VOID mode), and one without (VOID mode).
2093 ; The non-VOID case must have an else part.
2094 ; MODE is the mode of the result, not the comparison.
2095 ; The comparison is expected to return a zero/non-zero value.
2096 ; ??? Perhaps this should be a syntax-expr. Later.
2098 (define (e-if estate mode cond then . else)
2099 (if (> (length else) 1)
2100 (error "if: too many elements in `else' part" else))
2103 (if cond then (car else)))
2107 ; ??? Not sure this should live here.
2109 (define (-subr-read errtxt . arg-list)
2115 (let ((s (apply -subr-read (cons "define-subr" arg-list))))
2117 (current-subr-add! s))
2123 ; The argument to drn,drmn,drsn must be Scheme code (or a fixed subset
2124 ; thereof). .str/.sym are used in pmacros so it makes sense to include them
2126 (define .str string-append)
2127 (define .sym symbol-append)
2129 ; Given (expr1 expr2 expr3 expr4), for example,
2130 ; return (fn (fn (fn expr1 expr2) expr3) expr4).
2132 (define (rtx-combine fn exprs)
2133 (assert (not (null? exprs)))
2134 (letrec ((-rtx-combine (lambda (fn exprs result)
2142 (-rtx-combine fn (cdr exprs) (car exprs)))
2145 ; Called before a .cpu file is read in.
2148 (set! -rtx-func-table (make-hash-table 127))
2149 (set! -rtx-macro-table (make-hash-table 127))
2150 (set! -rtx-num-next 0)
2152 (reader-add-command! 'define-subr
2154 Define an rtx subroutine, name/value pair list version.
2156 nil 'arg-list define-subr)
2162 (define (rtl-builtin!)
2166 ; Called after cpu files are loaded to add misc. remaining entries to the
2167 ; rtx handler table for use during evaluation.
2168 ; rtl-finish! must be done before ifmt-compute!, the latter will
2169 ; construct hardware objects which is done by rtx evaluation.
2171 (define (rtl-finish!)
2172 (logit 2 "Building rtx operand table ...\n")
2174 ; Update s-pc, must be called after operand-init!.
2177 ; Table of traversers for the various rtx elements.
2178 (let ((hash-table (-rtx-make-traverser-table)))
2179 (set! -rtx-traverser-table (make-vector (rtx-max-num) #f))
2180 (for-each (lambda (rtx-name)
2181 (let ((rtx (rtx-lookup rtx-name)))
2183 (vector-set! -rtx-traverser-table (rtx-num rtx)
2187 (hashq-ref hash-table arg-type)))
2188 (rtx-arg-types rtx))))))
2191 ; Initialize the operand hash table.
2192 (set! -rtx-operand-table (make-hash-table 127))
2194 ; Add the operands to the eval symbol table.
2195 (for-each (lambda (op)
2196 (hashq-set! -rtx-operand-table (obj:name op) op)
2200 ; Add ifields to the eval symbol table.
2201 (for-each (lambda (f)
2202 (hashq-set! -rtx-operand-table (obj:name f) f)
2204 (non-derived-ifields (current-ifld-list)))