1 ; Routines for instruction semantic analysis.
2 ; Copyright (C) 2000, 2009 Red Hat, Inc.
3 ; This file is part of CGEN.
4 ; See file COPYING.CGEN for details.
6 ; Semantic expression compilation.
7 ; This is more involved than normal rtx compilation as we need to keep
8 ; track of the inputs and outputs. Various attributes that can be derived
9 ; from the code are also computed.
11 ; Subroutine of -rtx-find-op to determine if two modes are equivalent.
12 ; Two modes are equivalent if they're equal, or if their sem-mode fields
14 ; M1 and M2 are mode names.
16 (define (/rtx-mode-equiv? m1 m2)
18 (let ((mode1 (mode:lookup m1))
19 (mode2 (mode:lookup m2)))
20 (let ((s1 (mode:sem-mode mode1))
21 (s2 (mode:sem-mode mode2)))
22 (eq? (if s1 (obj:name s1) m1) (if s2 (obj:name s2) m2)))))
25 ; Subroutine of semantic-compile to find OP in OP-LIST.
26 ; OP-LIST is a list of operand expressions: (type expr mode name indx-sel).
27 ; The result is the list element or #f if not found.
28 ; TYPE is one of -op- reg mem.
29 ; EXPR is the constructed `xop' rtx expression for the operand,
30 ; ignored in the search.
31 ; MODE must match, as defined by /rtx-mode-equiv?.
32 ; NAME is the hardware element name, ifield name, or '-op-'.
33 ; INDX-SEL must match if present in either.
35 ; ??? Does this need to take "conditionally-referenced" into account?
37 (define (/rtx-find-op op op-list)
41 (indx-sel (car (cddddr op))))
42 ; The first cdr is to drop the dummy first arg.
43 (let loop ((op-list (cdr op-list)))
44 (cond ((null? op-list) #f)
45 ((eq? type (caar op-list))
46 (let ((try (car op-list)))
47 (if (and (eq? name (cadddr try))
48 (/rtx-mode-equiv? mode (caddr try))
49 (equal? indx-sel (car (cddddr try))))
51 (loop (cdr op-list)))))
52 (else (loop (cdr op-list))))))
55 ; Subroutine of semantic-compile to determine how the operand in
56 ; position OP-POS of EXPR is used.
57 ; The result is one of 'use, 'set, 'set-quiet.
58 ; "use" means "input operand".
60 (define (/rtx-ref-type expr op-pos)
61 ; operand 0 is the option list, operand 1 is the mode
62 ; (if you want to complain, fine, it's not like it would be unexpected)
66 ((set-quiet clobber) 'set-quiet)
71 ; Subroutine of semantic-compile:process-expr!, to simplify it.
72 ; Looks up the operand in the current set, returns it if found,
74 ; REF-TYPE is one of 'use, 'set, 'set-quiet.
75 ; Adds COND-CTI/UNCOND-CTI to SEM-ATTRS if the operand is a set of the pc.
77 (define (/build-operand! op-expr tstate ref-type op-list sem-attrs)
78 (let* ((orig-op (rtx-operand-obj op-expr (obj-isa-list (tstate-owner tstate))))
79 (mode (rtx-mode op-expr))
80 ;; We need a copy as we'll be modifying it.
81 (op (op:new-mode orig-op mode))
82 ;; The first #f is a placeholder for the object.
83 (try (list '-op- #f mode (rtx-arg1 op-expr) #f))
84 (existing-op (/rtx-find-op try op-list)))
86 (assert (not (eq? (op:mode-name op) 'DFLT)))
89 (memq ref-type '(set set-quiet)))
91 (list (if (tstate-cond? tstate) 'COND-CTI 'UNCOND-CTI))))
93 ; If already present, return the object, otherwise add it.
98 ; We can't set the operand number yet 'cus we don't know it.
99 ; However, when it's computed we'll need to set all associated
100 ; operands. This is done by creating shared rtx (a la gcc) - the
101 ; operand number then need only be updated in one place.
104 (op:set-cond?! op (tstate-cond? tstate))
105 ; Set the object rtx in `try', now that we have it.
106 (set-car! (cdr try) (rtx-make-xop op))
107 ; Add the operand to in/out-ops.
108 (append! op-list (list try))
112 ; Subroutine of semantic-compile:process-expr!, to simplify it.
114 (define (/build-reg-operand! expr tstate op-list)
115 (let* ((hw-name (rtx-reg-name expr))
116 (hw (current-hw-sem-lookup-1 hw-name)))
120 (let* ((mode (rtx-mode expr))
121 (indx-sel (rtx-reg-index-sel expr))
122 ; #f is a place-holder for the object (filled in later)
123 (try (list 'reg #f mode hw-name indx-sel))
124 (existing-op (/rtx-find-op try op-list)))
126 ; If already present, return the object, otherwise add it.
131 (let ((xop (apply reg (cons (tstate->estate tstate)
133 (cons hw-name indx-sel))))))
134 (op:set-cond?! xop (tstate-cond? tstate))
135 ; Set the object rtx in `try', now that we have it.
136 (set-car! (cdr try) (rtx-make-xop xop))
137 ; Add the operand to in/out-ops.
138 (append! op-list (list try))
141 (parse-error (tstate-context tstate) "unknown reg" expr)))
144 ; Subroutine of semantic-compile:process-expr!, to simplify it.
146 (define (/build-mem-operand! expr tstate op-list)
147 (let ((mode (rtx-mode expr))
148 (indx-sel (rtx-mem-index-sel expr)))
150 (let* ((try (list 'mem #f mode 'h-memory indx-sel))
151 (existing-op (/rtx-find-op try op-list)))
153 ; If already present, return the object, otherwise add it.
158 (let ((xop (apply mem (cons (tstate->estate tstate)
159 (cons mode indx-sel)))))
160 (op:set-cond?! xop (tstate-cond? tstate))
161 ; Set the object in `try', now that we have it.
162 (set-car! (cdr try) (rtx-make-xop xop))
163 ; Add the operand to in/out-ops.
164 (append! op-list (list try))
168 ; Subroutine of semantic-compile:process-expr!, to simplify it.
170 (define (/build-ifield-operand! expr tstate op-list)
171 (let* ((f-name (rtx-ifield-name expr))
172 (f (current-ifld-lookup f-name)))
175 (parse-error (tstate-context tstate) "unknown ifield" f-name))
177 (let* ((mode (obj:name (ifld-mode f)))
178 (try (list '-op- #f mode f-name #f))
179 (existing-op (/rtx-find-op try op-list)))
181 ; If already present, return the object, otherwise add it.
186 (let ((xop (make <operand> (obj-location f)
188 (atlist-cons (bool-attr-make 'SEM-ONLY #t)
190 (obj:name (ifld-hw-type f))
192 (make <hw-index> 'anonymous
193 'ifield (ifld-mode f) f)
195 (set-car! (cdr try) (rtx-make-xop xop))
196 (append! op-list (list try))
200 ; Subroutine of semantic-compile:process-expr!, to simplify it.
202 ; ??? There are various optimizations (both space usage in ARGBUF and time
203 ; spent in semantic code) that can be done on code that uses index-of
204 ; (see i960's movq insn). Later.
206 (define (/build-index-of-operand! expr tstate op-list)
207 (if (not (and (rtx? (rtx-index-of-value expr))
208 (rtx-kind? 'operand (rtx-index-of-value expr))))
209 (parse-error (tstate-context tstate)
210 "only `(index-of operand)' is currently supported"
213 (let ((op (rtx-operand-obj (rtx-index-of-value expr)
214 (obj-isa-list (tstate-owner tstate)))))
215 (let ((indx (op:index op)))
216 (if (not (eq? (hw-index:type indx) 'ifield))
217 (parse-error (tstate-context tstate)
218 "only ifield indices are currently supported"
220 (let* ((f (hw-index:value indx))
221 (f-name (obj:name f)))
222 ; The rest of this is identical to /build-ifield-operand!.
223 (let* ((mode (obj:name (ifld-mode f)))
224 (try (list '-op- #f mode f-name #f))
225 (existing-op (/rtx-find-op try op-list)))
227 ; If already present, return the object, otherwise add it.
232 (let ((xop (make <operand> (if (source-ident? f) (obj-location f) #f)
234 (atlist-cons (bool-attr-make 'SEM-ONLY #t)
236 (obj:name (ifld-hw-type f))
238 (make <hw-index> 'anonymous
241 ; (send (op:type op) 'get-index-mode)
244 (set-car! (cdr try) (rtx-make-xop xop))
245 (append! op-list (list try))
249 ; Build the tstate known value list for INSN.
250 ; This is built from the ifield-assertion list.
252 (define (insn-build-known-values insn)
253 (let ((expr (insn-ifield-assertion insn)))
255 (case (rtx-name expr)
257 (if (and (rtx-kind? 'ifield (rtx-cmp-op-arg expr 0))
258 (rtx-constant? (rtx-cmp-op-arg expr 1)))
259 (list (cons (rtx-ifield-name (rtx-cmp-op-arg expr 0))
260 (rtx-cmp-op-arg expr 1)))
263 (if (rtx-kind? 'ifield (rtx-member-value expr))
264 (list (cons (rtx-ifield-name (rtx-member-value expr))
265 (rtx-member-set expr)))
271 ; Structure to record the result of semantic-compile.
273 (define (csem-make compiled-code inputs outputs attributes)
274 (vector compiled-code inputs outputs attributes)
279 (define (csem-code csem) (vector-ref csem 0))
280 (define (csem-inputs csem) (vector-ref csem 1))
281 (define (csem-outputs csem) (vector-ref csem 2))
282 (define (csem-attrs csem) (vector-ref csem 3))
284 ; Traverse SEM-CODE, computing the input and output operands.
285 ; The result is an object of four elements (built with csem-make).
286 ; The first is a list of the canonical form of each element in SEM-CODE:
287 ; operand and ifield elements specified without `operand' or `ifield' have it
288 ; prepended, and operand numbers are computed for each operand.
289 ; Operand numbers are needed when emitting "write" handlers for LIW cpus.
290 ; Having the operand numbers available is also useful for efficient
291 ; modeling: recording operand references can be done with a bitmask (one host
292 ; insn), and the code to do the modeling can be kept out of the code that
294 ; The second is the list of input <operand> objects.
295 ; The third is the list of output <operand> objects.
296 ; The fourth is an <attr-list> object of attributes that can be computed from
298 ; The possibilities are: UNCOND-CTI, COND-CTI, SKIP-CTI, DELAY-SLOT.
299 ; ??? Combine *-CTI into an enum attribute.
301 ; CONTEXT is a <context> object or #f if there is none.
302 ; INSN is the <insn> object.
303 ; SEM-CODE must be canonicalized rtl.
305 ; ??? Specifying operand ordinals in the source would simplify this and speed
306 ; it up. On the other hand that makes the source form more complex. Maybe the
307 ; complexity will prove necessary, but following the goal of "incremental
308 ; complication", we don't do this yet.
309 ; Another way to simplify this and speed it up would be to add lists of
310 ; input/output operands to the instruction description.
312 ; ??? This calls rtx-simplify which calls rtx-traverse as it's simpler to
313 ; simplify EXPR first, and then compile it. On the other hand it's slower
314 ; (two calls to rtx-traverse!).
316 (define (semantic-compile context insn sem-code)
317 (assert (rtx? sem-code))
321 ; These record the result of traversing SEM-CODE.
322 ; They're lists of (type object mode name [args ...]).
323 ; TYPE is one of: -op- reg mem.
324 ; `-op-' is just something unique and is only used internally.
325 ; OBJECT is the constructed <operand> object.
326 ; The first element is just a dummy so that append! always works.
327 (in-ops (list (list #f)))
328 (out-ops (list (list #f)))
330 ; List of attributes computed from SEM-CODE.
331 ; The first element is just a dummy so that append! always works.
332 (sem-attrs (list #f))
334 ; Called for expressions encountered in SEM-CODE.
335 ; Don't waste cpu here, this is part of the slowest piece in CGEN.
337 (lambda (rtx-obj expr parent-expr op-pos tstate appstuff)
340 ;; NOTE: Despite the ! in, e.g., /build-reg-operand!,
341 ;; it does return a result.
344 ((reg) (let ((ref-type (/rtx-ref-type parent-expr op-pos))
345 ; ??? could verify reg is a scalar
346 (regno (or (rtx-reg-number expr) 0)))
347 ; The register number is either a number or an
349 ; ??? This is a departure from GCC RTL that might have
350 ; significant ramifications. On the other hand in cases
351 ; where it matters the expression could always be
352 ; required to reduce to a constant (or some such).
353 (cond ((number? regno) #t)
355 (rtx-traverse-operands rtx-obj expr tstate appstuff))
356 (else (parse-error (tstate-context tstate)
357 "invalid register number"
359 (/build-reg-operand! expr tstate
360 (if (eq? ref-type 'use)
365 ((mem) (let ((ref-type (/rtx-ref-type parent-expr op-pos)))
366 (rtx-traverse-operands rtx-obj expr tstate appstuff)
367 (/build-mem-operand! expr tstate
368 (if (eq? ref-type 'use)
373 ((operand) (let ((ref-type (/rtx-ref-type parent-expr op-pos)))
374 (/build-operand! expr tstate ref-type
375 (if (eq? ref-type 'use)
380 ; Give operand new name.
381 ((name) (let ((result (/rtx-traverse (caddr expr) 'RTX
382 parent-expr op-pos tstate appstuff)))
383 (if (not (operand? result))
384 (error "name: invalid argument:" expr result))
385 (op:set-sem-name! result (cadr expr))
386 ; (op:set-num! result (caddr expr))
389 ; Specify a reference to a local variable
390 ((local) expr) ; nothing to do
392 ; Instruction fields.
393 ((ifield) (let ((ref-type (/rtx-ref-type parent-expr op-pos)))
394 (if (not (eq? ref-type 'use))
395 (parse-error (tstate-context tstate)
396 "can't set an `ifield'" expr))
397 (/build-ifield-operand! expr tstate in-ops)))
400 ; For registers this is the register number.
401 ; For memory this is the address.
402 ; For constants, this is the constant.
403 ((index-of) (let ((ref-type (/rtx-ref-type parent-expr op-pos)))
404 (if (not (eq? ref-type 'use))
405 (parse-error (tstate-context tstate)
406 "can't set an `index-of'" expr))
407 (/build-index-of-operand! expr tstate in-ops)))
409 ; Machine generate the SKIP-CTI attribute.
410 ((skip) (append! sem-attrs (list 'SKIP-CTI)) #f)
412 ; Machine generate the DELAY-SLOT attribute.
413 ((delay) (append! sem-attrs (list 'DELAY-SLOT)) #f)
415 ; If this is a syntax expression, the operands won't have been
416 ; processed, so tell our caller we want it to by returning #f.
417 ; We do the same for non-syntax expressions to keep things
418 ; simple. This requires collaboration with the traversal
419 ; handlers which are defined to do what we want if we return #f.
422 ; Whew. We're now ready to traverse the expression.
423 ; Traverse the expression recording the operands and building objects
424 ; for most elements in the source representation.
425 ; This also performs various simplifications.
426 ; In particular machine dependent code for non-selected machines
428 (compiled-expr (rtx-traverse
431 (rtx-simplify context insn sem-code
432 (insn-build-known-values insn))
437 ;(display "in: ") (display in-ops) (newline)
438 ;(display "out: ") (display out-ops) (newline)
441 ; Now that we have the nub of all input and output operands,
442 ; we can assign operand numbers. Inputs and outputs are not defined
443 ; separately, output operand numbers follow inputs. This simplifies the
444 ; code which keeps track of such things: it can use one variable.
445 ; The assignment is defined to be arbitrary. If there comes a day
446 ; when we need to prespecify operand numbers, revisit.
447 ; The operand lists are sorted to avoid spurious differences in generated
448 ; code (for example unnecessary extra entries can be created in the
451 ; Drop dummy first arg and sort operand lists.
453 (alpha-sort-obj-list (map (lambda (op)
454 (rtx-xop-obj (cadr op)))
457 (alpha-sort-obj-list (map (lambda (op)
458 (rtx-xop-obj (cadr op)))
460 (sem-attrs (cdr sem-attrs)))
462 (let ((in-op-nums (iota (length sorted-ins)))
463 (out-op-nums (iota (length sorted-outs) (length sorted-ins))))
465 (for-each (lambda (op num) (op:set-num! op num))
466 sorted-ins in-op-nums)
467 (for-each (lambda (op num) (op:set-num! op num))
468 sorted-outs out-op-nums)
470 (let ((dump (lambda (op)
471 (string/symbol-append " "
474 (number->string (op:num op))
478 (map dump sorted-ins)
480 (map dump sorted-outs)
481 "End of operands.\n"))
483 (csem-make compiled-expr sorted-ins sorted-outs
484 (atlist-parse context sem-attrs "")))))
487 ; Traverse SEM-CODE, computing attributes derivable from it.
488 ; The result is an <attr-list> object of attributes that can be computed from
490 ; The possibilities are: UNCOND-CTI, COND-CTI, SKIP-CTI, DELAY-SLOT.
491 ; This computes the same values as semantic-compile, but for speed is
492 ; focused on attributes only.
493 ; ??? Combine *-CTI into an enum attribute.
495 ; CONTEXT is a <context> object or #f if there is none.
496 ; INSN is the <insn> object.
498 (define (semantic-attrs context insn sem-code)
499 (assert (rtx? sem-code))
503 ; List of attributes computed from SEM-CODE.
504 ; The first element is just a dummy so that append! always works.
505 (sem-attrs (list #f))
507 ; Called for expressions encountered in SEM-CODE.
509 (lambda (rtx-obj expr parent-expr op-pos tstate appstuff)
512 ;; FIXME: What's the result for the operand case?
513 ((operand) (if (and (eq? 'pc (rtx-operand-name expr))
514 (memq (/rtx-ref-type parent-expr op-pos)
517 (if (tstate-cond? tstate)
518 ; Don't change these to '(FOO), since
521 (list 'UNCOND-CTI)))))
522 ((skip) (append! sem-attrs (list 'SKIP-CTI)) #f)
523 ((delay) (append! sem-attrs (list 'DELAY-SLOT)) #f)
525 ; If this is a syntax expression, the operands won't have been
526 ; processed, so tell our caller we want it to by returning #f.
527 ; We do the same for non-syntax expressions to keep things
528 ; simple. This requires collaboration with the traversal
529 ; handlers which are defined to do what we want if we return #f.
532 ; Traverse the expression recording the attributes.
533 (traversed-expr (rtx-traverse
536 (rtx-simplify context insn sem-code
537 (insn-build-known-values insn))
543 ; Drop dummy first arg.
544 ((sem-attrs (cdr sem-attrs)))
545 (atlist-parse context sem-attrs "")))