OSDN Git Service

comment tweaks
[pf3gnuchains/sourceware.git] / cgen / iformat.scm
1 ; Instruction formats.
2 ; Copyright (C) 2000 Red Hat, Inc.
3 ; This file is part of CGEN.
4 ; See file COPYING.CGEN for details.
5
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.
9 ;
10 ; Two kinds of formats are defined here: iformat and sformat.
11 ; (pronounced "I-format" and "S-format")
12 ;
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.
16 ;
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.
24 ;
25 ; The "base length" is the length of the insn that is initially fetched for
26 ; decoding purposes.
27 ; Formats are fixed in length.  For variable instruction length architectures
28 ; there are separate formats for each insn's possible length.
29
30 (define <iformat>
31   (class-make '<iformat>
32               '(<ident>)
33                 ; From <ident>:
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
38                 ;   uses the format.
39               '(
40                 ; Index into the iformat table.
41                 number
42
43                 ; Sort key, used to determine insns with identical formats.
44                 key
45
46                 ; List of <ifield> objects.
47                 ifields
48
49                 ; min (insn-length, base-insn-size)
50                 mask-length
51
52                 ; total length of insns with this format
53                 length
54
55                 ; mask of base part
56                 mask
57
58                 ; An example insn that uses the format.
59                 eg-insn
60                 )
61               nil)
62 )
63
64 ; Accessor fns.
65
66 (define-getters <iformat> ifmt
67   (number key ifields mask-length length mask eg-insn)
68 )
69
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))
74            ifld-list)
75 )
76
77 ; Return enum cgen_fmt_type value for FMT.
78 ; ??? Not currently used.
79
80 (define (ifmt-enum fmt)
81   (string-append "@CPU@_" (string-upcase (gen-sym fmt)))
82 )
83 \f
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.
87
88 (define (compute-insn-length fld-list)
89   (apply + (map ifld-length (collect ifld-base-ifields fld-list)))
90 )
91
92 ; Given FLD-LIST, compute the base length in bits.
93 ;
94 ; For variable length instruction sets, or with cpus with multiple
95 ; instruction sets, compute the base appropriate for this set of
96 ; ifields.  Check that ifields are not shared among isas with
97 ; inconsistent base insn lengths.
98
99 (define (compute-insn-base-mask-length fld-list)
100   (let* ((isa-base-bitsizes
101           (remove-duplicates
102            (map isa-base-insn-bitsize
103                 (map current-isa-lookup
104                      (collect (lambda (ifld) 
105                                 (bitset-attr->list (atlist-attr-value (obj-atlist ifld) 'ISA #f)))
106                               fld-list))))))
107     (if (= 1 (length isa-base-bitsizes))
108         (min (car isa-base-bitsizes) (compute-insn-length fld-list))
109         (error "ifields have inconsistent isa/base-insn-size values:" isa-base-bitsizes)))
110 )
111
112 ; Given FLD-LIST, compute the bitmask of constant values in the base part
113 ; of the insn (i.e. the opcode field).
114 ;
115 ; FIXME: Need to add support for constant fields appearing outside the base
116 ; insn.  One way would be to record with each insn the value for each constant
117 ; field.  That would allow code to straightforwardly fetch it.  Another would
118 ; be to only record constant values appearing outside the base insn.
119 ;
120 ; See also (insn-value).
121 ;
122 (define (compute-insn-base-mask fld-list)
123   (let* ((mask-len (compute-insn-base-mask-length fld-list))
124          (lsb0? (ifld-lsb0? (car fld-list)))
125          (mask-bitrange (make <bitrange>
126                               0 ; word-offset
127                               (if lsb0? (- mask-len 1) 0) ; start
128                               mask-len ; length
129                               mask-len ; word-length
130                               lsb0?)))
131     (apply +
132            (map (lambda (fld) (ifld-mask fld mask-len mask-bitrange))
133                 ; Find the fields that have constant values.
134                 (find ifld-constant? (collect ifld-base-ifields fld-list)))
135            )
136     )
137 )
138 \f
139 ; Return the <iformat> search key for a sorted field list.
140 ; This determines how iformats differ from each other.
141 ; It also speeds up searching as the search key can be anything
142 ; (though at present searching isn't as fast as it could be).
143 ; INSN is passed so that we can include its sanytize attribute, if present,
144 ; so sanytized sources work (needed formats don't disappear).
145
146 (define (-ifmt-search-key insn sorted-ifld-list)
147   (string-map (lambda (ifld)
148                 (string-append " ("
149                                (or (obj-attr-value insn 'sanitize)
150                                    "-nosan-")
151                                " "
152                                (obj:name ifld)
153                                " "
154                                (ifld-ilk ifld)
155                                ")"))
156               sorted-ifld-list)
157 )
158
159 ; Create an <iformat> object for INSN.
160 ; INDEX is the ordinal to assign to the result or -1 if unknown.
161 ; SEARCH-KEY is the search key used to determine the iformat's uniqueness.
162 ; IFLDS is a sorted list of INSN's ifields.
163
164 (define (ifmt-build insn index search-key iflds)
165   (make <iformat>
166     (symbol-append 'ifmt- (obj:name insn))
167     (string-append "e.g. " (insn-syntax insn))
168     atlist-empty
169     index
170     search-key
171     iflds
172     (compute-insn-base-mask-length iflds)
173     (compute-insn-length iflds)
174     (compute-insn-base-mask iflds)
175     insn)
176 )
177 \f
178 ; Sformats.
179
180 (define <sformat>
181   (class-make '<sformat>
182               '(<ident>)
183               ; From <ident>:
184               ; - NAME is derived from number.
185               ; - COMMENT is the assembler syntax of an example insn that
186               ;   uses the format.
187               '(
188                 ; Index into the sformat table.
189                 number
190
191                 ; Sort key, used to determine insns with identical formats.
192                 key
193
194                 ; Non-#f if insns with this format are cti insns.
195                 cti?
196
197                 ; IN-OPS is a list of input operands.
198                 ; OUT-OPS is a list of output operands.
199                 ; These are used to distinguish the format from others,
200                 ; so that the extract and read operations can be based on the
201                 ; sformat.
202                 ; The extract fns use this data to record the necessary
203                 ; information for profiling [which isn't necessarily a property
204                 ; of the field list].  We could have one extraction function
205                 ; per instruction, but there's a *lot* of duplicated code, and
206                 ; the semantic operands rarely contribute to extra formats.
207                 ; The parallel execution support uses this data to record the
208                 ; input (or output) values based on the instruction format,
209                 ; again cutting down on duplicated code.
210                 in-ops
211                 out-ops
212
213                 ; Length of all insns with this format.
214                 ; Since insns with different iformats can have the same sformat
215                 ; we need to ensure ifield extraction works among the various
216                 ; iformats.  We do this by ensuring all insns with the same
217                 ; sformat have the same length.
218                 length
219
220                 ; Cached list of all ifields used.
221                 ; This can be derived from IN-OPS/OUT-OPS but is computed once
222                 ; and cached here for speed.
223                 iflds
224
225                 ; An example insn that uses the format.
226                 ; This is used for debugging purposes, but also to help get
227                 ; sanytization (spelled wrong on purpose) right.
228                 eg-insn
229
230                 ; <sformat-argbuf> entry
231                 ; FIXME: Temporary location, to be moved elsewhere
232                 (sbuf . #f)
233                 )
234               nil)
235 )
236
237 ; Accessor fns.
238
239 (define-getters <sformat> sfmt
240   (number key cti? in-ops out-ops length iflds eg-insn sbuf)
241 )
242
243 (define-setters <sformat> sfmt (sbuf))
244
245 (method-make-make! <sformat>
246                    '(name comment attrs
247                      number key cti? in-ops out-ops length iflds eg-insn)
248 )
249 \f
250 ; Return the <sformat> search key for a sorted field list and semantic
251 ; operands.
252 ; This determines how sformats differ from each other.
253 ; It also speeds up searching as the search key can be anything
254 ; (though at present searching isn't as fast as it could be).
255 ;
256 ; INSN is passed so that we can include its sanytize attribute, if present,
257 ; so sanytized sources work (needed formats don't disappear).
258 ; SORTED-USED-IFLDS is a sorted list of ifields used by SEM-{IN,OUT}-OPS.
259 ; Note that it is not the complete set of ifields used by INSN.
260 ;
261 ; We assume INSN's <iformat> has been recorded.
262 ;
263 ; Note: It's important to minimize the number of created sformats.  It keeps
264 ; the generated code smaller (and sometimes faster - more usable common
265 ; fragments in pbb simulators).  Don't cause spurious differences.
266
267 (define (-sfmt-search-key insn cti? sorted-used-iflds sem-in-ops sem-out-ops)
268   (let ((op-key (lambda (op)
269                   (string-append " ("
270                                  (or (obj-attr-value insn 'sanitize)
271                                      "-nosan-")
272                                  " "
273                                  (obj:name op)
274                                  ; ??? Including memory operands currently
275                                  ; isn't necessary and it can account for some
276                                  ; spurious differences.  On the other hand
277                                  ; leaving it out doesn't seem like the right
278                                  ; thing to do.
279                                  (if (memory? (op:type op))
280                                      ""
281                                      (string-append " "
282                                                     (obj:name (op:mode op))))
283                                  ; CGEN_OPERAND_INSTANCE_COND_REF is stored
284                                  ; with the operand in the operand instance
285                                  ; table thus formats must be distinguished
286                                  ; by this.
287                                  (if (op:cond? op) " cond" "")
288                                  ")")))
289         )
290     (list
291      cti?
292      (insn-length insn)
293      (string-map (lambda (ifld)
294                    (string-append " (" (obj:name ifld) " " (ifld-ilk ifld) ")"))
295                  sorted-used-iflds)
296      (string-map op-key
297                  sem-in-ops)
298      (string-map op-key
299                  sem-out-ops)
300      ))
301 )
302
303 ; Create an <sformat> object for INSN.
304 ; INDEX is the ordinal to assign to the result or -1 if unknown.
305 ; SEARCH-KEY is the search key used to determine the sformat's uniqueness.
306 ; {IN,OUT}-OPS are lists of INSN's input/output operands.
307 ; SORTED-USED-IFLDS is a sorted list of ifields used by {IN,OUT}-OPS.
308 ; Note that it is not the complete set of ifields used by INSN.
309 ;
310 ; We assume INSN's <iformat> has already been recorded.
311
312 (define (sfmt-build insn index search-key cti? in-ops out-ops sorted-used-iflds)
313   (make <sformat>
314     (symbol-append 'sfmt- (obj:name insn))
315     (string-append "e.g. " (insn-syntax insn))
316     atlist-empty
317     index
318     search-key
319     cti?
320     in-ops
321     out-ops
322     (insn-length insn)
323     sorted-used-iflds
324     insn)
325 )
326
327 ; Sort IFLDS by dependencies and then by starting bit number.
328
329 (define (-sfmt-order-iflds iflds)
330   (let ((up? 
331          ; ??? Something like this is preferable.
332          ;(not (ifld-lsb0? (car ifld-list)))
333          (not (current-arch-insn-lsb0?))))
334     (let loop ((independent nil) (dependent nil) (iflds iflds))
335       (cond ((null? iflds)
336              (append (sort-ifield-list independent up?)
337                      (sort-ifield-list dependent up?)))
338             ; FIXME: quick hack.
339             ((multi-ifield? (car iflds))
340              (loop independent (cons (car iflds) dependent) (cdr iflds)))
341             (else
342              (loop (cons (car iflds) independent) dependent (cdr iflds))))))
343 )
344
345 ; Return a sorted list of ifields used by IN-OPS, OUT-OPS.
346 ; The ifields are sorted by dependencies and then by start bit.
347 ; The important points are to help distinguish sformat's by the ifields used
348 ; and to put ifields that others depend on first.
349
350 (define (-sfmt-used-iflds in-ops out-ops)
351   (let ((in-iflds (map op-iflds-used in-ops))
352         (out-iflds (map op-iflds-used out-ops)))
353     (let ((all-iflds (nub (append (apply append in-iflds)
354                                   (apply append out-iflds))
355                           obj:name)))
356       (-sfmt-order-iflds all-iflds)))
357 )
358 \f
359 ; The format descriptor is used to sort formats.
360 ; This is a utility class internal to this file.
361 ; There is one instance per insn.
362
363 (define <fmt-desc>
364   (class-make '<fmt-desc>
365               nil
366               '(
367                 ; #t if insn is a cti insn
368                 cti?
369
370                 ; sorted list of insn's ifields
371                 iflds
372
373                 ; computed set of input/output operands
374                 in-ops out-ops
375
376                 ; set of ifields used by IN-OPS,OUT-OPS.
377                 used-iflds
378
379                 ; computed set of attributes
380                 attrs
381                 )
382               nil)
383 )
384
385 ; Accessors.
386
387 (define-getters <fmt-desc> -fmt-desc
388   (cti? iflds in-ops out-ops used-iflds attrs)
389 )
390
391 ; Compute an iformat descriptor used to build an <iformat> object for INSN.
392 ;
393 ; If COMPUTE-SFORMAT? is #t compile the semantics and compute the semantic
394 ; format (same as instruction format except that operands are used to
395 ; distinguish insns).
396 ; Attributes derivable from the semantics are also computed.
397 ; This is all done at the same time to minimize the number of times the
398 ; semantic code is traversed.
399 ;
400 ; The result is (descriptor compiled-semantics attrs).
401 ; `descriptor' is #f for insns with an empty field list
402 ; (this happens for virtual insns).
403 ; `compiled-semantics' is #f if COMPUTE-SFORMAT? is #f.
404 ; `attrs' is an <attr-list> object of attributes derived from the semantics.
405 ;
406 ; ??? We never traverse the semantics of virtual insns.
407
408 (define (ifmt-analyze insn compute-sformat?)
409   ; First sort by starting bit number the list of fields in INSN.
410   (let ((sorted-ifields
411          (sort-ifield-list (insn-iflds insn)
412                            ; ??? Something like this is preferable, but
413                            ; if the first insn is a virtual insn there are
414                            ; no fields.
415                            ;(not (ifld-lsb0? (car (insn-iflds insn))))
416                            (not (current-arch-insn-lsb0?))
417                            )))
418
419     (if (null? sorted-ifields)
420
421         ; Field list is unspecified.
422         (list #f #f atlist-empty)
423
424         ; FIXME: error checking (e.g. missing or overlapping bits)
425         (let* (; A list of the various bits of semantic code.
426                (sems (list (insn-semantics insn)))
427                ; Compute list of input and output operands if asked for.
428                (sem-ops (if compute-sformat?
429                             (semantic-compile #f ; FIXME: context
430                                               insn sems)
431                             (csem-make #f #f #f
432                                        (if (insn-semantics insn)
433                                            (semantic-attrs #f ; FIXME: context
434                                                            insn sems)
435                                            atlist-empty))))
436                )
437           (let ((compiled-sems (csem-code sem-ops))
438                 (in-ops (csem-inputs sem-ops))
439                 (out-ops (csem-outputs sem-ops))
440                 (attrs (csem-attrs sem-ops))
441                 (cti? (or (atlist-cti? (csem-attrs sem-ops))
442                           (insn-cti? insn))))
443             (list (make <fmt-desc>
444                     cti? sorted-ifields in-ops out-ops
445                     (if (and in-ops out-ops)
446                         (-sfmt-used-iflds in-ops out-ops)
447                         #f)
448                     attrs)
449                   compiled-sems
450                   attrs)))))
451 )
452
453 ; Subroutine of ifmt-compute!, to simplify it.
454 ; Lookup INSN's iformat in IFMT-LIST and if not found add it.
455 ; FMT-DESC is INSN's <fmt-desc> object.
456 ; IFMT-LIST is append!'d to and the found iformat is stored in INSN.
457
458 (define (-ifmt-lookup-ifmt! insn fmt-desc ifmt-list)
459   (let* ((search-key (-ifmt-search-key insn (-fmt-desc-iflds fmt-desc)))
460          (ifmt (find-first (lambda (elm)
461                              (equal? (ifmt-key elm) search-key))
462                            ifmt-list)))
463
464     (if ifmt
465
466         ; Format was found, use it.
467         (begin
468           (logit 3 "Using iformat " (number->string (ifmt-number ifmt)) ".\n")
469           (insn-set-ifmt! insn ifmt)
470           )
471
472         ; Format wasn't found, create new entry.
473         (let* ((ifmt-index (length ifmt-list))
474                (ifmt (ifmt-build insn ifmt-index search-key
475                                  (ifields-base-ifields (-fmt-desc-iflds fmt-desc)))))
476           (logit 3 "Creating iformat " (number->string ifmt-index) ".\n")
477           (insn-set-ifmt! insn ifmt)
478           (append! ifmt-list (list ifmt))
479           )
480         ))
481
482   *UNSPECIFIED*
483 )
484
485 ; Subroutine of ifmt-compute!, to simplify it.
486 ; Lookup INSN's sformat in SFMT-LIST and if not found add it.
487 ; FMT-DESC is INSN's <fmt-desc> object.
488 ; SFMT-LIST is append!'d to and the found sformat is stored in INSN.
489 ;
490 ; We assume INSN's <iformat> has already been recorded.
491
492 (define (-ifmt-lookup-sfmt! insn fmt-desc sfmt-list)
493   (let* ((search-key (-sfmt-search-key insn (-fmt-desc-cti? fmt-desc)
494                                        (-fmt-desc-used-iflds fmt-desc)
495                                        (-fmt-desc-in-ops fmt-desc)
496                                        (-fmt-desc-out-ops fmt-desc)))
497          (sfmt (find-first (lambda (elm)
498                              (equal? (sfmt-key elm) search-key))
499                            sfmt-list)))
500
501     (if sfmt
502
503         ; Format was found, use it.
504         (begin
505           (logit 3 "Using sformat " (number->string (sfmt-number sfmt)) ".\n")
506           (insn-set-sfmt! insn sfmt)
507           )
508
509         ; Format wasn't found, create new entry.
510         (let* ((sfmt-index (length sfmt-list))
511                (sfmt (sfmt-build insn sfmt-index search-key
512                                  (-fmt-desc-cti? fmt-desc)
513                                  (-fmt-desc-in-ops fmt-desc)
514                                  (-fmt-desc-out-ops fmt-desc)
515                                  (ifields-base-ifields (-fmt-desc-used-iflds fmt-desc)))))
516           (logit 3 "Creating sformat " (number->string sfmt-index) ".\n")
517           (insn-set-sfmt! insn sfmt)
518           (append! sfmt-list (list sfmt))
519           )
520         ))
521
522   *UNSPECIFIED*
523 )
524 \f
525 ; Main entry point.
526
527 ; Given a list of insns, compute the set of instruction formats, semantic
528 ; formats, semantic attributes, and compiled semantics for each insn.
529 ;
530 ; The computed <iformat> object is stored in the `ifmt' field of each insn.
531 ;
532 ; Attributes derived from the semantic code are added to the insn's attributes,
533 ; but they don't override any prespecified values.
534 ;
535 ; If COMPUTE-SFORMAT? is #t, the computed <sformat> object is stored in the
536 ; `sfmt' field of each insn, and the processed semantic code is stored in the
537 ; `compiled-semantics' field of each insn.
538 ;
539 ; The `fmt-desc' field of each insn is used to store an <fmt-desc> object
540 ; which contains the search keys, sorted field list, input-operands, and
541 ; output-operands, and is not used outside this procedure.
542 ;
543 ; The result is a list of two lists: the set of computed iformats, and the
544 ; set of computed sformats.
545 ;
546 ; *** This is the most expensive calculation in CGEN.   ***
547 ; *** (mainly because of the detailed semantic parsing) ***
548
549 (define (ifmt-compute! insn-list compute-sformat?)
550   (logit 2 "Computing instruction formats and analyzing semantics ...\n")
551
552   ; First analyze each insn, storing the result in fmt-desc.
553   ; If asked to, convert the semantic code to a compiled form to simplify more
554   ; intelligent processing of it later.
555
556   (for-each (lambda (insn)
557               (logit 3 "Scanning operands of " (obj:name insn) ": "
558                      (insn-syntax insn) " ...\n")
559               (let ((sem-ops (ifmt-analyze insn compute-sformat?)))
560                 (insn-set-fmt-desc! insn (car sem-ops))
561                 (if (and compute-sformat? (cadr sem-ops))
562                     (let ((compiled-sems (cadr sem-ops)))
563                       (insn-set-compiled-semantics! insn (car compiled-sems))))
564                 (obj-set-atlist! insn
565                                  (atlist-append (obj-atlist insn)
566                                                 (caddr sem-ops)))
567                 ))
568             insn-list)
569
570   ; Now for each insn, look up the ifield list in the format table (and if not
571   ; found add it), and set the ifmt/sfmt elements of the insn.
572
573   (let* ((empty-ifmt (make <iformat>
574                           'ifmt-empty
575                           "empty iformat for unspecified field list"
576                           atlist-empty ; attrs
577                           -1 ; number
578                           #f ; key
579                           nil ; fields
580                           0 ; mask-length
581                           0 ; length
582                           0 ; mask
583                           #f)) ; eg-insn
584          (empty-sfmt (make <sformat>
585                           'sfmt-empty
586                           "empty sformat for unspecified field list"
587                           atlist-empty ; attrs
588                           -1 ; number
589                           #f ; key
590                           #f ; cti?
591                           nil ; sem-in-ops
592                           nil ; sem-out-ops
593                           0 ; length
594                           nil ; used iflds
595                           #f)) ; eg-insn
596          (ifmt-list (list empty-ifmt))
597          (sfmt-list (list empty-sfmt))
598          )
599
600     (for-each (lambda (insn)
601                 (logit 3 "Processing format for " (obj:name insn) ": "
602                        (insn-syntax insn) " ...\n")
603
604                 (let ((fmt-desc (insn-fmt-desc insn)))
605
606                   (if fmt-desc
607
608                       (begin
609                         ; Must compute <iformat> before <sformat>, the latter
610                         ; needs the former.
611                         (-ifmt-lookup-ifmt! insn fmt-desc ifmt-list)
612                         (if compute-sformat?
613                             (-ifmt-lookup-sfmt! insn fmt-desc sfmt-list)))
614
615                       ; No field list present, use empty format.
616                       (begin
617                         (insn-set-ifmt! insn empty-ifmt)
618                         (if compute-sformat?
619                             (insn-set-sfmt! insn empty-sfmt))))))
620
621               (non-multi-insns insn-list))
622
623     ; Done.  Return the computed iformat and sformat lists.
624     (list ifmt-list sfmt-list)
625     )
626 )