2 ; Copyright (C) 2000 Red Hat, Inc.
3 ; This file is part of CGEN.
4 ; See file COPYING.CGEN for details.
6 ; Instruction formats are computed after the .cpu file has been read in.
7 ; ??? May also wish to allow programmer to specify formats, but not sure this
8 ; will complicate things more than it simplifies them, so it's defered.
10 ; Two kinds of formats are defined here: iformat and sformat.
11 ; (pronounced "I-format" and "S-format")
13 ; Iformats are the instruction format as specified by the instructions' fields,
14 ; and are the machine computed version of the generally known notion of an
15 ; "instruction format". No semantic information is attributed to iformats.
17 ; Sformats are the same as iformats except that semantics are used to
18 ; distinguish them. For example, if an operand is refered to in one mode by
19 ; one instruction and in a different mode by another instruction, then these
20 ; two insns would have different sformats but the same iformat. Sformats
21 ; are used in simulator extraction code to collapse the number of cases that
22 ; must be handled. They can also be used to collapse the number of cases
23 ; in the modeling code.
25 ; The "base length" is the length of the insn that is initially fetched for
27 ; Formats are fixed in length. For variable instruction length architectures
28 ; there are separate formats for each insn's possible length.
31 (class-make '<iformat>
34 ; - NAME is derived from number, but we might have user
35 ; specified formats someday [though I wouldn't add them
36 ; without a clear need].
37 ; - COMMENT is the assembler syntax of an example insn that
40 ; Index into the iformat table.
43 ; Sort key, used to determine insns with identical formats.
46 ; List of <ifield> objects.
49 ; min (insn-length, base-insn-size)
52 ; total length of insns with this format
58 ; An example insn that uses the format.
66 (define-getters <iformat> ifmt
67 (number key ifields mask-length length mask eg-insn)
70 ; Traverse the ifield list to collect all base (non-derived) ifields used in it.
71 (define (ifields-base-ifields ifld-list)
72 (collect (lambda (ifld)
73 (ifld-base-ifields ifld))
77 ; Return enum cgen_fmt_type value for FMT.
78 ; ??? Not currently used.
80 (define (ifmt-enum fmt)
81 (string-append "@CPU@_" (string-upcase (gen-sym fmt)))
84 ; Given FLD-LIST, compute the length of the insn in bits.
85 ; This is done by adding up all the field sizes.
86 ; All bits must be represent exactly once.
88 (define (compute-insn-length fld-list)
89 (apply + (map ifld-length (collect ifld-base-ifields fld-list)))
92 ; Given FLD-LIST, compute the base length in bits.
93 ; Computing the min of state-base-insn-bitsize and the total-length
94 ; is for [V]LIW instruction sets.
96 (define (compute-insn-base-mask-length fld-list)
97 (min (state-base-insn-bitsize) (compute-insn-length fld-list))
100 ; Given FLD-LIST, compute the bitmask of constant values in the base part
101 ; of the insn (i.e. the opcode field).
103 ; FIXME: Need to add support for constant fields appearing outside the base
104 ; insn. One way would be to record with each insn the value for each constant
105 ; field. That would allow code to straightforwardly fetch it. Another would
106 ; be to only record constant values appearing outside the base insn.
108 ; See also (insn-value).
110 (define (compute-insn-base-mask fld-list)
111 (let* ((mask-len (compute-insn-base-mask-length fld-list))
112 (lsb0? (ifld-lsb0? (car fld-list)))
113 (mask-bitrange (make <bitrange>
115 (if lsb0? (- mask-len 1) 0) ; start
117 mask-len ; word-length
120 (map (lambda (fld) (ifld-mask fld mask-len mask-bitrange))
121 ; Find the fields that have constant values.
122 (find ifld-constant? (collect ifld-base-ifields fld-list)))
127 ; Return the <iformat> search key for a sorted field list.
128 ; This determines how iformats differ from each other.
129 ; It also speeds up searching as the search key can be anything
130 ; (though at present searching isn't as fast as it could be).
131 ; INSN is passed so that we can include its sanytize attribute, if present,
132 ; so sanytized sources work (needed formats don't disappear).
134 (define (-ifmt-search-key insn sorted-ifld-list)
135 (string-map (lambda (ifld)
137 (or (obj-attr-value insn 'sanitize)
147 ; Create an <iformat> object for INSN.
148 ; INDEX is the ordinal to assign to the result or -1 if unknown.
149 ; SEARCH-KEY is the search key used to determine the iformat's uniqueness.
150 ; IFLDS is a sorted list of INSN's ifields.
152 (define (ifmt-build insn index search-key iflds)
154 (symbol-append 'ifmt- (obj:name insn))
155 (string-append "e.g. " (insn-syntax insn))
160 (compute-insn-base-mask-length iflds)
161 (compute-insn-length iflds)
162 (compute-insn-base-mask iflds)
169 (class-make '<sformat>
172 ; - NAME is derived from number.
173 ; - COMMENT is the assembler syntax of an example insn that
176 ; Index into the sformat table.
179 ; Sort key, used to determine insns with identical formats.
182 ; Non-#f if insns with this format are cti insns.
185 ; IN-OPS is a list of input operands.
186 ; OUT-OPS is a list of output operands.
187 ; These are used to distinguish the format from others,
188 ; so that the extract and read operations can be based on the
190 ; The extract fns use this data to record the necessary
191 ; information for profiling [which isn't necessarily a property
192 ; of the field list]. We could have one extraction function
193 ; per instruction, but there's a *lot* of duplicated code, and
194 ; the semantic operands rarely contribute to extra formats.
195 ; The parallel execution support uses this data to record the
196 ; input (or output) values based on the instruction format,
197 ; again cutting down on duplicated code.
201 ; Length of all insns with this format.
202 ; Since insns with different iformats can have the same sformat
203 ; we need to ensure ifield extraction works among the various
204 ; iformats. We do this by ensuring all insns with the same
205 ; sformat have the same length.
208 ; Cached list of all ifields used.
209 ; This can be derived from IN-OPS/OUT-OPS but is computed once
210 ; and cached here for speed.
213 ; An example insn that uses the format.
214 ; This is used for debugging purposes, but also to help get
215 ; sanytization (spelled wrong on purpose) right.
218 ; <sformat-argbuf> entry
219 ; FIXME: Temporary location, to be moved elsewhere
227 (define-getters <sformat> sfmt
228 (number key cti? in-ops out-ops length iflds eg-insn sbuf)
231 (define-setters <sformat> sfmt (sbuf))
233 (method-make-make! <sformat>
235 number key cti? in-ops out-ops length iflds eg-insn)
238 ; Return the <sformat> search key for a sorted field list and semantic
240 ; This determines how sformats differ from each other.
241 ; It also speeds up searching as the search key can be anything
242 ; (though at present searching isn't as fast as it could be).
244 ; INSN is passed so that we can include its sanytize attribute, if present,
245 ; so sanytized sources work (needed formats don't disappear).
246 ; SORTED-USED-IFLDS is a sorted list of ifields used by SEM-{IN,OUT}-OPS.
247 ; Note that it is not the complete set of ifields used by INSN.
249 ; We assume INSN's <iformat> has been recorded.
251 ; Note: It's important to minimize the number of created sformats. It keeps
252 ; the generated code smaller (and sometimes faster - more usable common
253 ; fragments in pbb simulators). Don't cause spurious differences.
255 (define (-sfmt-search-key insn cti? sorted-used-iflds sem-in-ops sem-out-ops)
256 (let ((op-key (lambda (op)
258 (or (obj-attr-value insn 'sanitize)
262 ; ??? Including memory operands currently
263 ; isn't necessary and it can account for some
264 ; spurious differences. On the other hand
265 ; leaving it out doesn't seem like the right
267 (if (memory? (op:type op))
270 (obj:name (op:mode op))))
271 ; CGEN_OPERAND_INSTANCE_COND_REF is stored
272 ; with the operand in the operand instance
273 ; table thus formats must be distinguished
275 (if (op:cond? op) " cond" "")
281 (string-map (lambda (ifld)
282 (string-append " (" (obj:name ifld) " " (ifld-ilk ifld) ")"))
291 ; Create an <sformat> object for INSN.
292 ; INDEX is the ordinal to assign to the result or -1 if unknown.
293 ; SEARCH-KEY is the search key used to determine the sformat's uniqueness.
294 ; {IN,OUT}-OPS are lists of INSN's input/output operands.
295 ; SORTED-USED-IFLDS is a sorted list of ifields used by {IN,OUT}-OPS.
296 ; Note that it is not the complete set of ifields used by INSN.
298 ; We assume INSN's <iformat> has already been recorded.
300 (define (sfmt-build insn index search-key cti? in-ops out-ops sorted-used-iflds)
302 (symbol-append 'sfmt- (obj:name insn))
303 (string-append "e.g. " (insn-syntax insn))
315 ; Sort IFLDS by dependencies and then by starting bit number.
317 (define (-sfmt-order-iflds iflds)
319 ; ??? Something like this is preferable.
320 ;(not (ifld-lsb0? (car ifld-list)))
321 (not (current-arch-insn-lsb0?))))
322 (let loop ((independent nil) (dependent nil) (iflds iflds))
324 (append (sort-ifield-list independent up?)
325 (sort-ifield-list dependent up?)))
327 ((multi-ifield? (car iflds))
328 (loop independent (cons (car iflds) dependent) (cdr iflds)))
330 (loop (cons (car iflds) independent) dependent (cdr iflds))))))
333 ; Return a sorted list of ifields used by IN-OPS, OUT-OPS.
334 ; The ifields are sorted by dependencies and then by start bit.
335 ; The important points are to help distinguish sformat's by the ifields used
336 ; and to put ifields that others depend on first.
338 (define (-sfmt-used-iflds in-ops out-ops)
339 (let ((in-iflds (map op-iflds-used in-ops))
340 (out-iflds (map op-iflds-used out-ops)))
341 (let ((all-iflds (nub (append (apply append in-iflds)
342 (apply append out-iflds))
344 (-sfmt-order-iflds all-iflds)))
347 ; The format descriptor is used to sort formats.
348 ; This is a utility class internal to this file.
349 ; There is one instance per insn.
352 (class-make '<fmt-desc>
355 ; #t if insn is a cti insn
358 ; sorted list of insn's ifields
361 ; computed set of input/output operands
364 ; set of ifields used by IN-OPS,OUT-OPS.
367 ; computed set of attributes
375 (define-getters <fmt-desc> -fmt-desc
376 (cti? iflds in-ops out-ops used-iflds attrs)
379 ; Compute an iformat descriptor used to build an <iformat> object for INSN.
381 ; If COMPUTE-SFORMAT? is #t compile the semantics and compute the semantic
382 ; format (same as instruction format except that operands are used to
383 ; distinguish insns).
384 ; Attributes derivable from the semantics are also computed.
385 ; This is all done at the same time to minimize the number of times the
386 ; semantic code is traversed.
388 ; The result is (descriptor compiled-semantics attrs).
389 ; `descriptor' is #f for insns with an empty field list
390 ; (this happens for virtual insns).
391 ; `compiled-semantics' is #f if COMPUTE-SFORMAT? is #f.
392 ; `attrs' is an <attr-list> object of attributes derived from the semantics.
394 ; ??? We never traverse the semantics of virtual insns.
396 (define (ifmt-analyze insn compute-sformat?)
397 ; First sort by starting bit number the list of fields in INSN.
398 (let ((sorted-ifields
399 (sort-ifield-list (insn-iflds insn)
400 ; ??? Something like this is preferable, but
401 ; if the first insn is a virtual insn there are
403 ;(not (ifld-lsb0? (car (insn-iflds insn))))
404 (not (current-arch-insn-lsb0?))
407 (if (null? sorted-ifields)
409 ; Field list is unspecified.
410 (list #f #f atlist-empty)
412 ; FIXME: error checking (e.g. missing or overlapping bits)
413 (let* (; A list of the various bits of semantic code.
414 (sems (list (insn-semantics insn)))
415 ; Compute list of input and output operands if asked for.
416 (sem-ops (if compute-sformat?
417 (semantic-compile #f ; FIXME: context
420 (if (insn-semantics insn)
421 (semantic-attrs #f ; FIXME: context
425 (let ((compiled-sems (csem-code sem-ops))
426 (in-ops (csem-inputs sem-ops))
427 (out-ops (csem-outputs sem-ops))
428 (attrs (csem-attrs sem-ops))
429 (cti? (or (atlist-cti? (csem-attrs sem-ops))
431 (list (make <fmt-desc>
432 cti? sorted-ifields in-ops out-ops
433 (if (and in-ops out-ops)
434 (-sfmt-used-iflds in-ops out-ops)
441 ; Subroutine of ifmt-compute!, to simplify it.
442 ; Lookup INSN's iformat in IFMT-LIST and if not found add it.
443 ; FMT-DESC is INSN's <fmt-desc> object.
444 ; IFMT-LIST is append!'d to and the found iformat is stored in INSN.
446 (define (-ifmt-lookup-ifmt! insn fmt-desc ifmt-list)
447 (let* ((search-key (-ifmt-search-key insn (-fmt-desc-iflds fmt-desc)))
448 (ifmt (find-first (lambda (elm)
449 (equal? (ifmt-key elm) search-key))
454 ; Format was found, use it.
456 (logit 3 "Using iformat " (number->string (ifmt-number ifmt)) ".\n")
457 (insn-set-ifmt! insn ifmt)
460 ; Format wasn't found, create new entry.
461 (let* ((ifmt-index (length ifmt-list))
462 (ifmt (ifmt-build insn ifmt-index search-key
463 (ifields-base-ifields (-fmt-desc-iflds fmt-desc)))))
464 (logit 3 "Creating iformat " (number->string ifmt-index) ".\n")
465 (insn-set-ifmt! insn ifmt)
466 (append! ifmt-list (list ifmt))
473 ; Subroutine of ifmt-compute!, to simplify it.
474 ; Lookup INSN's sformat in SFMT-LIST and if not found add it.
475 ; FMT-DESC is INSN's <fmt-desc> object.
476 ; SFMT-LIST is append!'d to and the found sformat is stored in INSN.
478 ; We assume INSN's <iformat> has already been recorded.
480 (define (-ifmt-lookup-sfmt! insn fmt-desc sfmt-list)
481 (let* ((search-key (-sfmt-search-key insn (-fmt-desc-cti? fmt-desc)
482 (-fmt-desc-used-iflds fmt-desc)
483 (-fmt-desc-in-ops fmt-desc)
484 (-fmt-desc-out-ops fmt-desc)))
485 (sfmt (find-first (lambda (elm)
486 (equal? (sfmt-key elm) search-key))
491 ; Format was found, use it.
493 (logit 3 "Using sformat " (number->string (sfmt-number sfmt)) ".\n")
494 (insn-set-sfmt! insn sfmt)
497 ; Format wasn't found, create new entry.
498 (let* ((sfmt-index (length sfmt-list))
499 (sfmt (sfmt-build insn sfmt-index search-key
500 (-fmt-desc-cti? fmt-desc)
501 (-fmt-desc-in-ops fmt-desc)
502 (-fmt-desc-out-ops fmt-desc)
503 (-fmt-desc-used-iflds fmt-desc))))
504 (logit 3 "Creating sformat " (number->string sfmt-index) ".\n")
505 (insn-set-sfmt! insn sfmt)
506 (append! sfmt-list (list sfmt))
515 ; Given a list of insns, compute the set of instruction formats, semantic
516 ; formats, semantic attributes, and compiled semantics for each insn.
518 ; The computed <iformat> object is stored in the `ifmt' field of each insn.
520 ; Attributes derived from the semantic code are added to the insn's attributes,
521 ; but they don't override any prespecified values.
523 ; If COMPUTE-SFORMAT? is #t, the computed <sformat> object is stored in the
524 ; `sfmt' field of each insn, and the processed semantic code is stored in the
525 ; `compiled-semantics' field of each insn.
527 ; The `fmt-desc' field of each insn is used to store an <fmt-desc> object
528 ; which contains the search keys, sorted field list, input-operands, and
529 ; output-operands, and is not used outside this procedure.
531 ; The result is a list of two lists: the set of computed iformats, and the
532 ; set of computed sformats.
534 ; *** This is the most expensive calculation in CGEN. ***
535 ; *** (mainly because of the detailed semantic parsing) ***
537 (define (ifmt-compute! insn-list compute-sformat?)
538 (logit 2 "Computing instruction formats and analyzing semantics ...\n")
540 ; First analyze each insn, storing the result in fmt-desc.
541 ; If asked to, convert the semantic code to a compiled form to simplify more
542 ; intelligent processing of it later.
544 (for-each (lambda (insn)
545 (logit 3 "Scanning operands of " (obj:name insn) ": "
546 (insn-syntax insn) " ...\n")
547 (let ((sem-ops (ifmt-analyze insn compute-sformat?)))
548 (insn-set-fmt-desc! insn (car sem-ops))
549 (if (and compute-sformat? (cadr sem-ops))
550 (let ((compiled-sems (cadr sem-ops)))
551 (insn-set-compiled-semantics! insn (car compiled-sems))))
552 (obj-set-atlist! insn
553 (atlist-append (obj-atlist insn)
558 ; Now for each insn, look up the ifield list in the format table (and if not
559 ; found add it), and set the ifmt/sfmt elements of the insn.
561 (let* ((empty-ifmt (make <iformat>
563 "empty iformat for unspecified field list"
572 (empty-sfmt (make <sformat>
574 "empty sformat for unspecified field list"
584 (ifmt-list (list empty-ifmt))
585 (sfmt-list (list empty-sfmt))
588 (for-each (lambda (insn)
589 (logit 3 "Processing format for " (obj:name insn) ": "
590 (insn-syntax insn) " ...\n")
592 (let ((fmt-desc (insn-fmt-desc insn)))
597 ; Must compute <iformat> before <sformat>, the latter
599 (-ifmt-lookup-ifmt! insn fmt-desc ifmt-list)
601 (-ifmt-lookup-sfmt! insn fmt-desc sfmt-list)))
603 ; No field list present, use empty format.
605 (insn-set-ifmt! insn empty-ifmt)
607 (insn-set-sfmt! insn empty-sfmt))))))
609 (non-multi-insns insn-list))
611 ; Done. Return the computed iformat and sformat lists.
612 (list ifmt-list sfmt-list)