2 ; Copyright (C) 2000, 2001, 2009 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
35 ; must be accessed via obj:name
39 ; ??? Not used I think, but keep.
42 ; result mode, or #f if from arg 2
43 ; (or the containing expression when canonicalizing)
46 ; types of each argument, as symbols
47 ; This is #f for macros.
49 ; OPTIONS - optional list of keyword-prefixed options
50 ; ANYINTMODE - any integer mode
51 ; ANYFLOATMODE - any floating point mode
52 ; ANYNUMMODE - any numeric mode
53 ; ANYEXPRMODE - VOID, PTR, or any numeric mode
54 ; EXPLNUMMODE - explicit numeric mode, can't be DFLT or VOID
55 ; VOIDORNUMMODE - VOID or any numeric mode
56 ; VOIDMODE - must be `VOID'
57 ; BIMODE - BI (boolean or bit int)
58 ; INTMODE - must be `INT'
59 ; SYMMODE - must be SYM
60 ; INSNMODE - must be INSN
61 ; MACHMODE - must be MACH
63 ; SETRTX - any rtx allowed to be `set'
64 ; TESTRTX - the test of an `if'
65 ; CONDRTX - a cond expression ((test) rtx ... rtx)
66 ; CASERTX - a case expression ((symbol .. symbol) rtx ... rtx)
67 ; LOCALS - the locals list of a sequence
68 ; ITERATION - the iteration
69 ; SYMBOLLIST - used for ISA name lists
70 ; ENVSTACK - environment stack
71 ; ATTRS - attribute list
72 ; SYMBOL - arg must be a symbol
73 ; STRING - arg must be a string
74 ; NUMBER - arg must be a number
75 ; SYMORNUM - arg must be a symbol or number
76 ; OBJECT - arg is an object (FIXME: restrict to <operand>?)
79 ; required mode of each argument
80 ; This is #f for macros.
81 ; Possible values include any mode name and:
83 ; ANYINT - any integer mode
85 ; MATCHEXPR - mode has to match the mode specified in the
86 ; containing expression
87 ; NOTE: This isn't necessarily the mode of the
88 ; result of the expression. E.g. in `set', the
89 ; result always has mode VOID, but the mode
90 ; specified in the expression is the mode of the
92 ; MATCHSEQ - for sequences
93 ; last expression has to match mode of sequence,
94 ; preceding expressions must be VOID
95 ; MATCH2 - must match mode of arg 2
96 ; MATCH3 - must match mode of arg 3
97 ; <MODE-NAME> - must match specified mode
100 ; arg number of the MATCHEXPR arg,
101 ; or #f if there is none
105 ; This is #f for macros.
106 ; ARG - operand, local, const
107 ; SET - set, set-quiet
108 ; UNARY - not, inv, etc.
109 ; BINARY - add, sub, etc.
110 ; TRINARY - addc, subc, etc.
111 ; COMPARE - eq, ne, etc.
114 ; SEQUENCE - sequence, parallel
116 ; MISC - everything else
119 ; A symbol indicating the flavour of rtx node this is.
120 ; FUNCTION - normal function
121 ; SYNTAX - don't pre-eval arguments
122 ; OPERAND - result is an operand
123 ; MACRO - converts one rtx expression to another
124 ; The word "style" was chosen to be sufficiently different
125 ; from "type", "kind", and "class".
128 ; A function to perform the rtx.
131 ; Ordinal number of rtx. Used to index into tables.
139 (define (rtx-func? x) (class-instance? <rtx-func> x))
143 (define-getters <rtx-func> rtx
144 (result-mode arg-types arg-modes matchexpr-index class style evaluator num)
147 (define (rtx-style-syntax? rtx) (eq? (rtx-style rtx) 'syntax))
149 ; Add standard `get-name' method since this isn't a subclass of <ident>.
151 (method-make! <rtx-func> 'get-name (lambda (self) (elm-get self 'name)))
153 ; List of mode types for arg-types.
155 (define /rtx-valid-mode-types
157 ANYINTMODE ANYFLOATMODE ANYNUMMODE ANYEXPRMODE EXPLNUMMODE VOIDORNUMMODE
158 VOIDMODE BIMODE INTMODE SYMMODE INSNMODE MACHMODE
162 ; List of valid values for arg-types, not including mode names.
164 (define /rtx-valid-types
167 /rtx-valid-mode-types
168 '(RTX SETRTX TESTRTX CONDRTX CASERTX)
169 '(LOCALS ITERATION SYMBOLLIST ENVSTACK ATTRS)
170 '(SYMBOL STRING NUMBER SYMORNUM OBJECT)
174 ; List of valid mode matchers, excluding mode names.
176 (define /rtx-valid-matches
177 '(ANY ANYINT NA MATCHEXPR MATCHSEQ MATCH2 MATCH3)
180 ;; Return arg number of MATCHEXPR in ARG-MODES or #f if not present.
182 (define (/rtx-find-matchexpr-index arg-modes)
183 ;; We can't use find-first-index here because arg-modes can be an
184 ;; improper list (a b c . d).
185 ;;(find-first-index 0 (lambda (t) (eq? t 'MATCHEXPR)) arg-modes)
186 (define (improper-find-first-index i pred l)
189 (cond ((pred (car l)) i)
190 (else (improper-find-first-index (+ 1 i) pred (cdr l)))))
193 (improper-find-first-index 0 (lambda (t) (eq? t 'MATCHEXPR)) arg-modes)
196 ; List of all defined rtx names. This can be map'd over without having
197 ; to know the innards of /rtx-func-table (which is a hash table).
199 (define /rtx-name-list nil)
200 (define (rtx-name-list) /rtx-name-list)
202 ; Table of rtx function objects.
203 ; This is set in rtl-init!.
205 (define /rtx-func-table nil)
207 ; Look up the <rtx-func> object for RTX-KIND.
208 ; Returns the object or #f if not found.
209 ; RTX-KIND is the name of the rtx function.
211 (define (rtx-lookup rtx-kind)
212 (assert (symbol? rtx-kind))
213 (hashq-ref /rtx-func-table rtx-kind)
216 ; Table of rtx macro objects.
217 ; This is set in rtl-init!.
219 (define /rtx-macro-table nil)
221 ; Table of operands, modes, and other non-functional aspects of RTL.
222 ; This is defined in rtl-finish!, after all operands have been read in.
224 (define /rtx-operand-table nil)
226 ; Number of next rtx to be defined.
228 (define /rtx-num-next #f)
230 ; Return the number of rtx's.
232 (define (rtx-max-num)
238 ; Add an entry to the rtx function table.
239 ; NAME-ARGS is a list of the operation name and arguments.
240 ; The mode of the result must be the first element in `args' (if there are
242 ; ARG-TYPES is a list of argument types (/rtx-valid-types).
243 ; ARG-MODES is a list of mode matchers (/rtx-valid-matches).
244 ; CLASS is the class of the rtx to be created.
245 ; ACTION is a list of Scheme expressions to perform the operation.
247 ; ??? Note that we can support variables. Not sure it should be done.
249 (define (def-rtx-node name-args result-mode arg-types arg-modes class action)
250 (let* ((name (car name-args))
251 (args (cdr name-args))
252 (context (make-prefix-context (string-append "defining rtx "
253 (symbol->string name))))
254 (matchexpr-index (/rtx-find-matchexpr-index arg-modes)))
256 ; (map1-improper (lambda (arg-type)
257 ; (if (not (memq arg-type /rtx-valid-types))
258 ; (context-error context "While defining rtx functions"
259 ; "invalid arg type" arg-type)))
261 ; (map1-improper (lambda (arg-mode)
262 ; (if (and (not (memq arg-mode /rtx-valid-matches))
263 ; (not (symbol? arg-mode))) ;; FIXME: mode-name?
264 ; (context-error context "While defining rtx functions"
265 ; "invalid arg mode match" arg-mode)))
268 (let ((rtx (make <rtx-func> name args
269 result-mode arg-types arg-modes matchexpr-index
274 (cons '*estate* args)
278 ; Add it to the table of rtx handlers.
279 (hashq-set! /rtx-func-table name rtx)
280 (set! /rtx-num-next (+ /rtx-num-next 1))
281 (set! /rtx-name-list (cons name /rtx-name-list))
285 (define define-rtx-node
286 ; Written this way so Hobbit can handle it.
287 (defmacro:syntax-transformer (lambda arg-list
288 (apply def-rtx-node arg-list)
292 ; Same as define-rtx-node but don't pre-evaluate the arguments.
293 ; Remember that `mode' must be the first argument.
295 (define (def-rtx-syntax-node name-args result-mode arg-types arg-modes class action)
296 (let ((name (car name-args))
297 (args (cdr name-args))
298 (matchexpr-index (/rtx-find-matchexpr-index arg-modes)))
299 (let ((rtx (make <rtx-func> name args
300 result-mode arg-types arg-modes matchexpr-index
305 (cons '*estate* args)
309 ; Add it to the table of rtx handlers.
310 (hashq-set! /rtx-func-table name rtx)
311 (set! /rtx-num-next (+ /rtx-num-next 1))
312 (set! /rtx-name-list (cons name /rtx-name-list))
316 (define define-rtx-syntax-node
317 ; Written this way so Hobbit can handle it.
318 (defmacro:syntax-transformer (lambda arg-list
319 (apply def-rtx-syntax-node arg-list)
323 ; Same as define-rtx-node but return an operand (usually an <operand> object).
324 ; ??? `mode' must be the first argument?
326 (define (def-rtx-operand-node name-args result-mode arg-types arg-modes class action)
327 ; Operand nodes must specify an action.
329 (let ((name (car name-args))
330 (args (cdr name-args))
331 (matchexpr-index (/rtx-find-matchexpr-index arg-modes)))
332 (let ((rtx (make <rtx-func> name args
333 result-mode arg-types arg-modes matchexpr-index
337 (cons '*estate* args)
340 ; Add it to the table of rtx handlers.
341 (hashq-set! /rtx-func-table name rtx)
342 (set! /rtx-num-next (+ /rtx-num-next 1))
343 (set! /rtx-name-list (cons name /rtx-name-list))
347 (define define-rtx-operand-node
348 ; Written this way so Hobbit can handle it.
349 (defmacro:syntax-transformer (lambda arg-list
350 (apply def-rtx-operand-node arg-list)
354 ; Convert one rtx expression into another.
355 ; NAME-ARGS is a list of the operation name and arguments.
356 ; ACTION is a list of Scheme expressions to perform the operation.
357 ; The result of ACTION must be another rtx expression (a list).
359 (define (def-rtx-macro-node name-args action)
360 ; macro nodes must specify an action
362 (let ((name (car name-args))
363 (args (cdr name-args)))
364 (let ((rtx (make <rtx-func> name args #f #f #f #f
367 (eval1 (list 'lambda args action))
369 ; Add it to the table of rtx macros.
370 (hashq-set! /rtx-macro-table name rtx)
371 (set! /rtx-num-next (+ /rtx-num-next 1))
372 (set! /rtx-name-list (cons name /rtx-name-list))
376 (define define-rtx-macro-node
377 ; Written this way so Hobbit can handle it.
378 (defmacro:syntax-transformer (lambda arg-list
379 (apply def-rtx-macro-node arg-list)
383 ; RTL macro expansion.
384 ; RTL macros are different than pmacros. The difference is that the expansion
385 ; happens internally, RTL macros are part of the language.
387 ; Lookup MACRO-NAME and return its <rtx-func> object or #f if not found.
389 (define (/rtx-macro-lookup macro-name)
390 (hashq-ref /rtx-macro-table macro-name)
393 ; Lookup (car exp) and return the macro's lambda if it is one or #f.
395 (define (/rtx-macro-check exp fn-getter)
396 (let ((macro (hashq-ref /rtx-macro-table (car exp))))
404 (define (/rtx-macro-expand-list exp fn-getter)
405 (let ((macro (/rtx-macro-check exp fn-getter)))
407 (apply macro (map (lambda (x) (/rtx-macro-expand x fn-getter))
409 (map (lambda (x) (/rtx-macro-expand x fn-getter))
413 ; Main entry point to expand a macro invocation.
415 (define (/rtx-macro-expand exp fn-getter)
416 (if (pair? exp) ; pair? -> cheap (and (not (null? exp)) (list? exp))
417 (let ((result (/rtx-macro-expand-list exp fn-getter)))
418 ; If the result is a new macro invocation, recurse.
420 (let ((macro (/rtx-macro-check result fn-getter)))
422 (/rtx-macro-expand (apply macro (cdr result)) fn-getter)
428 ; Publically accessible version.
430 (define rtx-macro-expand /rtx-macro-expand)
434 ; Get implied mode of X, either an operand expression, sequence temp, or
435 ; a hardware reference expression.
436 ; The result is the name of the mode.
438 (define (rtx-lvalue-mode-name estate x)
441 ; ((operand) (obj:name (op:mode (current-op-lookup (cadr x) (obj-isa-list (estate-owner estate))))))
442 ((xop) (obj:name (send (rtx-xop-obj x) 'get-mode)))
444 ; (if (eq? (rtx-opspec-mode x) 'VOID)
445 ; (rtx-lvalue-mode-name estate (rtx-opspec-hw-ref x))
446 ; (rtx-opspec-mode x)))
447 ; ((reg mem) (cadr x))
448 ((local) ;; (local options mode name)
449 (let* ((name (cadddr x))
450 (temp (rtx-temp-lookup (estate-env-stack estate) name)))
452 (estate-error estate "unknown local" name))
453 (obj:name (rtx-temp-mode temp))))
456 "rtx-lvalue-mode-name: not an operand or hardware reference:"
460 ; Lookup the mode to use for semantic operations (unsigned modes aren't
461 ; allowed since we don't have ANDUSI, etc.).
462 ; MODE is a <mode> object.
463 ; ??? I have actually implemented both ways (full use of unsigned modes
464 ; and mostly hidden use of unsigned modes). Neither makes me real
465 ; comfortable, though I liked bringing unsigned modes out into the open
466 ; even if it doubled the number of semantic operations.
468 (define (rtx-sem-mode mode) (or (mode:sem-mode mode) mode))
470 ; Return the mode of object OBJ.
472 (define (rtx-obj-mode obj) (send obj 'get-mode))
474 ; Return a boolean indicating of modes M1,M2 are compatible.
475 ; M1,M2 are <mode> objects.
477 (define (rtx-mode-compatible? m1 m2)
478 ;; ??? This is more permissive than is perhaps proper.
479 (let ((mode1 (rtx-sem-mode m1))
480 (mode2 (rtx-sem-mode m2)))
481 ;;(eq? (obj:name mode1) (obj:name mode2)))
482 (mode-compatible? 'sameclass mode1 mode2))
485 ; Environments (sequences with local variables).
487 ; Temporaries are created within a sequence.
488 ; MODE is a <mode> object.
489 ; VALUE is #f if not set yet.
490 ; e.g. (sequence ((WI tmp)) (set tmp reg0) ...)
491 ; ??? Perhaps what we want here is `let' but for now I prefer `sequence'.
492 ; This isn't exactly `let' either as no initial value is specified.
493 ; Environments are also used to specify incoming values from the top level.
495 (define <rtx-temp> (class-make '<rtx-temp> nil '(name mode value) nil))
497 ;(define cx-temp:name (elm-make-getter <c-expr-temp> 'name))
498 ;(define cx-temp:mode (elm-make-getter <c-expr-temp> 'mode))
499 ;(define cx-temp:value (elm-make-getter <c-expr-temp> 'value))
501 (define-getters <rtx-temp> rtx-temp (name mode value))
505 (lambda (self name mode value)
506 (assert (mode? mode))
507 (elm-set! self 'name name)
508 (elm-set! self 'mode mode)
509 (elm-set! self 'value (if value value (gen-temp name)))
513 (define (gen-temp name)
514 ; ??? calls to gen-c-symbol don't belong here
515 (string-append "tmp_" (gen-c-symbol name))
518 ; Return a boolean indicating if X is an <rtx-temp>.
520 (define (rtx-temp? x) (class-instance? <rtx-temp> x))
522 ; Respond to 'get-mode messages.
524 (method-make! <rtx-temp> 'get-mode (lambda (self) (elm-get self 'mode)))
526 ; Respond to 'get-name messages.
528 (method-make! <rtx-temp> 'get-name (lambda (self) (elm-get self 'name)))
530 ; An environment is a list of <rtx-temp> objects.
531 ; An environment stack is a list of environments.
533 (define (rtx-env-stack-empty? env-stack) (null? env-stack))
534 (define (rtx-env-stack-head env-stack) (car env-stack))
535 (define (rtx-env-empty-stack) nil)
536 (define (rtx-env-init-stack1 vars-alist)
537 (if (null? vars-alist)
539 (cons (rtx-env-make vars-alist) nil))
541 (define (rtx-env-empty? env) (null? env))
543 ;; Create an environment from VAR-ALIST,
544 ;; an alist of (name <mode>-or-mode-name value) elements,
545 ;; or, in the case of /rtx-closure-make, a list of (name . <rtx-temp>).
547 (define (rtx-env-make var-alist)
548 ;; Check for an already-compiled environment, for /rtx-closure-make's sake.
549 (if (and (pair? var-alist)
550 (rtx-temp? (cdar var-alist)))
552 ;; Convert VAR-ALIST to an associative list of <rtx-temp> objects.
553 (map (lambda (var-spec)
557 (mode-maybe-lookup (cadr var-spec))
562 ; Create an initial environment with local variables.
563 ; VAR-LIST is a list of (mode-name name) elements, i.e. the locals argument to
564 ; `sequence' or equivalent thereof.
566 (define (rtx-env-make-locals var-list)
567 ; Convert VAR-LIST to an associative list of <rtx-temp> objects.
568 (map (lambda (var-spec)
569 (cons (cadr var-spec)
571 (cadr var-spec) (mode:lookup (car var-spec)) #f)))
575 ; Return the symbol name of the limit variable of `do-count'
576 ; given iteration-variable ITER-VAR.
577 ; ??? We don't publish that this variable is available to use, but we could.
579 (define (rtx-make-iteration-limit-var iter-var)
580 (symbol-append iter-var '-limit)
583 ; Create an environment with the iteration local variables of `do-count'.
585 (define (rtx-env-make-iteration-locals iter-var)
586 (rtx-env-make-locals (list (list 'INT iter-var)
587 (list 'INT (rtx-make-iteration-limit-var iter-var))))
590 ;; Convert an alist of (name <mode>-object-or-name value) to
593 (define (rtx-var-alist-to-env var-alist) var-alist)
595 ;; Convert an alist of (name <mode>-object-or-name value) to
596 ;; an environment stack.
598 (define (rtx-var-alist-to-closure-env-stack var-alist)
599 ;; Preserve emptiness so (null? env-stack) works.
600 (if (null? var-alist)
605 ;; Convert the source form of an env-stack, e.g. as used in a closure,
606 ;; to the internal form, which is (name <rtx-temp>-object).
608 (define (rtx-make-env-stack closure-env-stack)
609 (map rtx-env-make closure-env-stack)
612 ; Push environment ENV onto the front of environment stack ENV-STACK,
613 ; returning a new object. ENV-STACK is not modified.
615 (define (rtx-env-push env-stack env)
619 ; Lookup variable NAME in environment stack ENV-STACK.
620 ; The result is the <rtx-temp> object.
622 (define (rtx-temp-lookup env-stack name)
623 (let loop ((stack env-stack))
626 (let ((temp (assq-ref (car stack) name)))
629 (loop (cdr stack))))))
632 ; Create a "closure" of EXPR using the current ISA list and temp stack.
633 ; MODE is the mode name.
635 (define (/rtx-closure-make estate mode expr)
636 ;; NOTE: This records the "compiled" environment stack in the closure.
637 (rtx-make 'closure mode (estate-isas estate) (estate-env-stack estate)
641 (define (rtx-env-stack-dump env-stack)
642 (let ((stack env-stack))
643 (if (rtx-env-stack-empty? stack)
644 (display "rtx-env stack (empty):\n")
645 (let loop ((stack stack) (level 0))
649 (display "rtx-env stack, level ")
652 (for-each (lambda (var)
654 ;(display (obj:name (rtx-temp-mode (cdr var))))
656 (display (rtx-temp-name (cdr var)))
659 (loop (cdr stack) (+ level 1)))))))
662 ; Build, test, and analyze various kinds of rtx's.
663 ; ??? A lot of this could be machine generated except that I don't yet need
666 (define (rtx-make kind . args)
667 (cons kind (rtx-munge-mode&options (rtx-lookup kind) 'DFLT kind args))
670 (define rtx-name car)
671 (define (rtx-kind? kind rtx) (eq? kind (rtx-name rtx)))
673 (define (rtx-make-const mode value) (rtx-make 'const mode value))
674 (define (rtx-make-enum mode value) (rtx-make 'enum mode value))
676 (define (rtx-constant? rtx) (memq (rtx-name rtx) '(const enum)))
678 ; Return value of constant RTX (either const or enum).
679 (define (rtx-constant-value rtx)
681 ((const) (rtx-const-value rtx))
682 ((enum) (car (enum-lookup-val (rtx-enum-value rtx))))
683 (else (error "rtx-constant-value: not const or enum" rtx)))
686 (define rtx-options cadr)
687 (define rtx-mode caddr)
688 (define rtx-args cdddr)
689 (define rtx-arg1 cadddr)
690 (define (rtx-arg2 rtx) (car (cddddr rtx)))
692 (define rtx-const-value rtx-arg1)
693 (define rtx-enum-value rtx-arg1)
695 (define rtx-reg-name rtx-arg1)
697 ; Return register number or #f if absent.
698 ; (reg options mode hw-name [regno [selector]])
699 (define (rtx-reg-number rtx) (list-maybe-ref rtx 4))
701 ; Return register selector or #f if absent.
702 (define (rtx-reg-selector rtx) (list-maybe-ref rtx 5))
704 ; Return both register number and selector.
705 (define rtx-reg-index-sel cddddr)
707 ; Return memory address.
708 (define rtx-mem-addr rtx-arg1)
710 ; Return memory selector or #f if absent.
711 (define (rtx-mem-sel mem) (list-maybe-ref mem 4))
713 ; Return both memory address and selector.
714 (define rtx-mem-index-sel cdddr)
716 ; Return MEM with new address NEW-ADDR.
717 ; ??? Complicate as necessary.
718 (define (rtx-change-address mem new-addr)
726 ; Return argument to `symbol' rtx.
727 (define rtx-symbol-name rtx-arg1)
729 (define (rtx-make-ifield mode-name ifield-name)
730 (rtx-make 'ifield mode-name ifield-name)
732 (define (rtx-ifield? rtx) (eq? 'ifield (rtx-name rtx)))
733 (define (rtx-ifield-name rtx)
734 (let ((ifield (rtx-arg1 rtx)))
739 (define (rtx-ifield-obj rtx)
740 (let ((ifield (rtx-arg1 rtx)))
742 (current-ifld-lookup ifield)
746 (define (rtx-make-operand mode-name op-name)
747 (rtx-make 'operand mode-name op-name)
749 (define (rtx-operand? rtx) (eq? 'operand (rtx-name rtx)))
750 ;; FIXME: This should just fetch rtx-arg1,
751 ;; operand rtxes shouldn't have objects, that's what xop is for.
752 (define (rtx-operand-name rtx)
753 (let ((operand (rtx-arg1 rtx)))
754 (if (symbol? operand)
759 ;; Given an operand rtx, return the <operand> object.
760 ;; RTX must be canonical rtl.
761 ;; ISA-NAME-LIST is the list of ISAs to look the operand up in.
763 ;; NOTE: op:mode-name can be DFLT, which means use the mode of the type.
764 ;; It is up to the caller to deal with it.
766 (define (rtx-operand-obj rtx isa-name-list)
767 (let ((op (current-op-lookup (rtx-arg1 rtx) isa-name-list))
768 (mode-name (rtx-mode rtx)))
770 (assert (not (eq? mode-name 'DFLT)))
771 ;; Ensure requested mode is supported by the hardware.
772 ;; rtx-canonicalize should have verified this already (I think).
773 (assert (hw-mode-ok? (op:type op) mode-name (op:index op)))
777 (define (rtx-make-local mode-name local-name)
778 (rtx-make 'local mode-name local-name)
780 (define (rtx-local? rtx) (eq? 'local (rtx-name rtx)))
781 (define (rtx-local-name rtx)
782 (let ((local (rtx-arg1 rtx)))
787 (define (rtx-local-obj rtx)
788 (let ((local (rtx-arg1 rtx)))
790 (error "can't use rtx-local-obj on local name")
794 (define (rtx-make-xop op)
795 (rtx-make 'xop (op:mode-name op) op)
797 (define rtx-xop-obj rtx-arg1)
799 ;(define (rtx-opspec? rtx) (eq? 'opspec (rtx-name rtx)))
800 ;(define (rtx-opspec-mode rtx) (rtx-mode rtx))
801 ;(define (rtx-opspec-hw-ref rtx) (list-ref rtx 5))
802 ;(define (rtx-opspec-set-op-num! rtx num) (set-car! (cddddr rtx) num))
804 (define rtx-index-of-value rtx-arg1)
806 (define (rtx-make-set dest src) (rtx-make 'set dest src))
807 (define rtx-set-dest rtx-arg1)
808 (define rtx-set-src rtx-arg2)
809 (define (rtx-single-set? rtx) (memq (car rtx) '(set set-quiet)))
811 (define rtx-alu-op-mode rtx-mode)
812 (define (rtx-alu-op-arg rtx n) (list-ref rtx (+ n 3)))
814 (define (rtx-boolif-op-arg rtx n) (list-ref rtx (+ n 3)))
816 (define rtx-cmp-op-mode rtx-mode)
817 (define (rtx-cmp-op-arg rtx n) (list-ref rtx (+ n 3)))
819 (define rtx-number-list-values cdddr)
821 (define rtx-member-value rtx-arg1)
822 (define (rtx-member-set rtx) (list-ref rtx 4))
824 (define rtx-if-mode rtx-mode)
825 (define (rtx-if-test rtx) (rtx-arg1 rtx))
826 (define (rtx-if-then rtx) (list-ref rtx 4))
827 ; If `else' clause is missing the result is #f.
828 (define (rtx-if-else rtx) (list-maybe-ref rtx 5))
830 (define (rtx-eq-attr-owner rtx) (list-ref rtx 3))
831 (define (rtx-eq-attr-attr rtx) (list-ref rtx 4))
832 (define (rtx-eq-attr-value rtx) (list-ref rtx 5))
834 (define (rtx-sequence-locals rtx) (cadddr rtx))
835 (define (rtx-sequence-exprs rtx) (cddddr rtx))
837 ; Same as rtx-sequence-locals except return in assq'able form.
838 ; ??? Sometimes I think it should have been (sequence ((name MODE)) ...)
839 ; instead of (sequence ((MODE name)) ...) from the beginning, sigh.
841 (define (rtx-sequence-assq-locals rtx)
842 (let ((locals (rtx-sequence-locals rtx)))
844 (list (cadr local) (car local)))
848 (define (rtx-closure-isas rtx) (list-ref rtx 3))
849 (define (rtx-closure-env-stack rtx) (list-ref rtx 4))
850 (define (rtx-closure-expr rtx) (list-ref rtx 5))
852 ; Return a semi-pretty string describing RTX.
853 ; This is used by hw to include the index in the element's name.
855 (define (rtx-pretty-name rtx)
858 ((const) (number->string (rtx-const-value rtx)))
859 ((operand) (symbol->string (rtx-operand-name rtx)))
860 ((local) (symbol->string (rtx-local-name rtx)))
861 ((xop) (symbol->string (obj:name (rtx-xop-obj rtx))))
863 (if (null? (cdr rtx))
864 (rtx-pretty-name (car rtx))
865 (apply stringsym-append
866 (cons (rtx-pretty-name (car rtx))
868 (string-append "-" (rtx-pretty-name elm)))
873 ; Various rtx utilities.
875 ; Dump an rtx expression.
877 (define (rtx-dump rtx)
878 (cond ((list? rtx) (map rtx-dump rtx))
879 ((object? rtx) (string/symbol-append "#<object "
880 (object-class-name rtx)
887 ; Dump an expression to a string.
889 (define (rtx-strdump rtx)
890 (with-output-to-string
892 ;; Use write instead of display, we want strings displayed with quotes.
893 (write (rtx-dump rtx))))
896 ;; Return the pretty-printed from of RTX.
898 (define (rtx-pretty-strdump rtx)
899 (with-output-to-string
901 (pretty-print (rtx-dump rtx))))
904 ; Return a boolean indicating if EXPR is known to be a compile-time constant.
906 (define (rtx-compile-time-constant? expr)
911 ((memq expr '(FALSE TRUE)) #t)
915 ; Return boolean indicating if EXPR has side-effects.
916 ; FIXME: for now punt.
918 (define (rtx-side-effects? expr)
922 ; Return a boolean indicating if EXPR is a "true" boolean value.
924 ; ??? In RTL, #t is a synonym for (const 1). This is confusing for Schemers,
925 ; so maybe RTL's #t should be renamed to TRUE.
927 (define (rtx-true? expr)
930 ((const enum) (!= (rtx-constant-value expr) 0))
932 ((eq? expr 'TRUE) #t)
936 ; Return a boolean indicating if EXPR is a "false" boolean value.
938 ; ??? In RTL, #f is a synonym for (const 0). This is confusing for Schemers,
939 ; so maybe RTL's #f should be renamed to FALSE.
941 (define (rtx-false? expr)
944 ((const enum) (= (rtx-constant-value expr) 0))
946 ((eq? expr 'FALSE) #t)
950 ; Return canonical boolean values.
952 (define (rtx-false) (rtx-make-const 'BI 0))
953 (define (rtx-true) (rtx-make-const 'BI 1))
955 ; Convert EXPR to a canonical boolean if possible.
957 (define (rtx-canonical-bool expr)
958 (cond ((rtx-side-effects? expr) expr)
959 ((rtx-false? expr) (rtx-false))
960 ((rtx-true? expr) (rtx-true))
964 ; Return rtx values for #f/#t.
966 (define (rtx-make-bool value)
972 ; Return #t if X is an rtl expression.
973 ; e.g. '(add WI dr simm8);
977 (and (pair? x) ; pair? -> cheap non-null-list?
978 (or (hashq-ref /rtx-func-table (car x))
979 (hashq-ref /rtx-macro-table (car x)))))
982 ; Instruction field support.
984 ; Return list of ifield names refered to in EXPR.
985 ; Assumes EXPR is more than just (ifield x).
987 (define (rtl-find-ifields expr)
989 (letrec ((scan! (lambda (arg-list)
990 (for-each (lambda (arg)
992 (if (eq? (car arg) 'ifield)
994 (cons (rtx-ifield-name arg)
999 (nub ifields identity)))
1002 ; Hardware rtx handlers.
1004 ; Subroutine of hw to compute the object's name.
1005 ; The name of the operand must include the index so that multiple copies
1006 ; of a hardware object (e.g. h-gr[0], h-gr[14]) can be distinguished.
1007 ; We make some attempt to make the name pretty as it appears in generated
1010 (define (/rtx-hw-name hw hw-name index-arg)
1011 (cond ((hw-scalar? hw)
1014 (symbolstr-append hw-name '- (rtx-pretty-name index-arg)))
1016 (symbolstr-append hw-name ; (obj:name (op:type self))
1018 ; (obj:name (op:index self)))))
1019 (stringize index-arg "-"))))
1022 ; Return the <operand> object described by
1023 ; HW-NAME/MODE-NAME/SELECTOR/INDEX-ARG.
1025 ; HW-NAME is the name of the hardware element.
1026 ; MODE-NAME is the name of the mode.
1027 ; INDEX-ARG is an rtx or number of the index.
1028 ; In the case of scalar hardware elements, pass 0 for INDEX-ARG.
1029 ; In the case of a vector of registers, INDEX-ARG is the vector index.
1030 ; SELECTOR is an rtx or number and is passed to HW-NAME to allow selection of a
1031 ; particular variant of the hardware. It's kind of like an INDEX, but along
1032 ; an atypical axis. An example is memory ASI's on Sparc. Pass
1033 ; hw-selector-default if there is no selector.
1034 ; ESTATE is the current rtx evaluation state.
1036 ; *** The index is passed unevaluated because for parallel execution support
1037 ; *** a variable is created with a name based on the hardware element and
1038 ; *** index, and we want a reasonably simple and stable name. We get this by
1039 ; *** stringize-ing it.
1040 ; *** ??? Though this needs to be redone anyway.
1042 ; ??? The specified hardware element must be either a scalar or a vector.
1043 ; Maybe in the future allow arrays although there's significant utility in
1044 ; allowing only at most a scalar index.
1046 (define (/hw estate mode-name hw-name index-arg selector)
1047 ; Enforce some rules to keep things in line with the current design.
1048 (if (not (symbol? mode-name))
1049 (parse-error (estate-context estate) "invalid mode name" mode-name))
1050 (if (not (symbol? hw-name))
1051 (parse-error (estate-context estate) "invalid hw name" hw-name))
1052 (if (not (or (number? index-arg)
1054 (parse-error (estate-context estate) "invalid index" index-arg))
1055 (if (not (or (number? selector)
1057 (parse-error (estate-context estate) "invalid selector" selector))
1059 (let ((hw (current-hw-sem-lookup-1 hw-name)))
1061 (parse-error (estate-context estate) "invalid hardware element" hw-name))
1063 (let* ((mode (if (eq? mode-name 'DFLT) (hw-mode hw) (mode:lookup mode-name)))
1064 (hw-name-with-mode (symbol-append hw-name '- (obj:name mode)))
1065 (index-mode (if (eq? hw-name 'h-memory) 'AI 'INT))
1066 (result (if (hw-pc? hw)
1068 (new <operand>)))) ; ??? lookup-for-new?
1071 (parse-error (estate-context estate) "invalid mode" mode-name))
1073 ; Record the selector.
1074 (elm-xset! result 'selector selector)
1076 ; Create the index object.
1077 (elm-xset! result 'index
1078 (cond ((number? index-arg)
1079 (make <hw-index> 'anonymous 'constant UINT index-arg))
1081 ; Make sure constant indices are recorded as such.
1082 (case (rtx-name index-arg)
1084 (make <hw-index> 'anonymous 'constant UINT
1085 (rtx-constant-value index-arg)))
1087 (make-enum-hw-index 'anonymous (rtx-enum-value index-arg)))
1089 (make <hw-index> 'anonymous 'rtx (mode:lookup index-mode)
1090 (/rtx-closure-make estate index-mode index-arg)))))
1091 (else (parse-error (estate-context estate)
1092 "invalid index" index-arg))))
1094 (if (not (hw-mode-ok? hw (obj:name mode) (elm-xget result 'index)))
1095 (parse-error (estate-context estate)
1096 "invalid mode for hardware" mode-name))
1098 (elm-xset! result 'hw-name hw-name)
1099 (elm-xset! result 'type hw)
1100 (elm-xset! result 'mode-name mode-name)
1101 (elm-xset! result 'mode mode)
1103 (op:set-pretty-sem-name! result hw-name)
1105 ; The name of the operand must include the index so that multiple copies
1106 ; of a hardware object (e.g. h-gr[0], h-gr[14]) can be distinguished.
1107 (let ((name (if (hw-pc? hw)
1109 (/rtx-hw-name hw hw-name-with-mode index-arg))))
1110 (send result 'set-name! name)
1111 (op:set-sem-name! result name))
1113 ; Empty comment and attribute.
1114 ; ??? Stick the arguments in the comment for debugging purposes?
1115 (send result 'set-comment! "")
1116 (send result 'set-atlist! atlist-empty)
1121 ; This is shorthand for (hw estate mode hw-name regno selector).
1122 ; ESTATE is the current rtx evaluation state.
1123 ; INDX-SEL is an optional register number and possible selector.
1124 ; The register number, if present, is (car indx-sel) and must be a number or
1125 ; unevaluated canonical RTX expression.
1126 ; The selector, if present, is (cadr indx-sel) and must be a number or
1127 ; unevaluated canonical RTX expression.
1128 ; ??? A register selector isn't supported yet. It's just an idea that's
1129 ; been put down on paper for future reference.
1131 (define (reg estate mode-name hw-name . indx-sel)
1132 (s-hw estate mode-name hw-name
1133 (if (pair? indx-sel) (car indx-sel) 0)
1134 (if (and (pair? indx-sel) (pair? (cdr indx-sel)))
1136 hw-selector-default))
1139 ; This is shorthand for (hw estate mode-name h-memory addr selector).
1140 ; ADDR must be an unevaluated canonical RTX expression.
1141 ; If present (car sel) must be a number or unevaluated canonical
1144 (define (mem estate mode-name addr . sel)
1145 (s-hw estate mode-name 'h-memory addr
1146 (if (pair? sel) (car sel) hw-selector-default))
1149 ; For the rtx nodes to use.
1153 ; The program counter.
1154 ; When this code is loaded, global `pc' is nil, it hasn't been set to the
1155 ; pc operand yet (see operand-init!). We can't use `pc' inside the drn as the
1156 ; value is itself. So we use s-pc. rtl-finish! must be called after
1161 ; Conditional execution.
1163 ; `if' in RTL has a result, like ?: in C.
1164 ; We support both: one with a result (non VOID mode), and one without (VOID mode).
1165 ; The non-VOID case must have an else part.
1166 ; MODE is the mode of the result, not the comparison.
1167 ; The comparison is expected to return a zero/non-zero value.
1168 ; ??? Perhaps this should be a syntax-expr. Later.
1170 (define (e-if estate mode cond then . else)
1171 (if (> (length else) 1)
1172 (estate-error estate "if: too many elements in `else' part" else))
1175 (if cond then (car else)))
1179 ; ??? Not sure this should live here.
1181 (define (/subr-read context . arg-list)
1187 (let ((s (apply /subr-read (cons "define-subr" arg-list))))
1189 (current-subr-add! s))
1195 ; The argument to drn,drmn,drsn must be Scheme code (or a fixed subset
1196 ; thereof). .str/.sym are used in pmacros so it makes sense to include them
1199 (define .str string-append)
1200 (define .sym symbol-append)
1202 ; Given (expr1 expr2 expr3 expr4), for example,
1203 ; return (fn (fn (fn expr1 expr2) expr3) expr4).
1205 (define (rtx-combine fn exprs)
1206 (assert (not (null? exprs)))
1207 (letrec ((-rtx-combine (lambda (fn exprs result)
1215 (-rtx-combine fn (cdr exprs) (car exprs)))
1218 ; Called before a .cpu file is read in.
1221 (set! /rtx-func-table (make-hash-table 127))
1222 (set! /rtx-macro-table (make-hash-table 127))
1223 (set! /rtx-num-next 0)
1227 ; All rtx take options for the first arg and a mode for the second.
1228 (for-each (lambda (rtx-name)
1229 (let ((rtx (rtx-lookup rtx-name)))
1232 (if (null? (rtx-arg-types rtx))
1233 #f ; pc is the one exception, blech
1235 (assert (eq? (car (rtx-arg-types rtx)) 'OPTIONS))
1236 (assert (memq (cadr (rtx-arg-types rtx)) /rtx-valid-mode-types)))))
1241 (reader-add-command! 'define-subr
1243 Define an rtx subroutine, name/value pair list version.
1245 nil 'arg-list define-subr)
1252 (define (rtl-builtin!)
1253 (rtx-init-traversal-tables!)
1258 ; Called after cpu files are loaded to add misc. remaining entries to the
1259 ; rtx handler table for use during evaluation.
1260 ; rtl-finish! must be done before ifmt-compute!, the latter will
1261 ; construct hardware objects which is done by rtx evaluation.
1263 (define (rtl-finish!)
1264 (logit 2 "Building rtx operand table ...\n")
1266 ; Update s-pc, must be called after operand-init!.
1269 ; Initialize the operand hash table.
1270 (set! /rtx-operand-table (make-hash-table 127))
1272 ; Add the operands to the eval symbol table.
1273 (for-each (lambda (op)
1274 (hashq-set! /rtx-operand-table (obj:name op) op))
1277 ; Add ifields to the eval symbol table.
1278 (for-each (lambda (f)
1279 (hashq-set! /rtx-operand-table (obj:name f) f))
1280 (non-derived-ifields (current-ifld-list)))