OSDN Git Service

1717f38d2c9f46976a5a1501bd123ad8b9624360
[pf3gnuchains/pf3gnuchains4x.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 ; Computing the min of state-base-insn-bitsize and the total-length
94 ; is for [V]LIW instruction sets.
95
96 (define (compute-insn-base-mask-length fld-list)
97   (min (state-base-insn-bitsize) (compute-insn-length fld-list))
98 )
99
100 ; Given FLD-LIST, compute the bitmask of constant values in the base part
101 ; of the insn (i.e. the opcode field).
102 ;
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.
107 ;
108 ; See also (insn-value).
109 ;
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>
114                               0 ; word-offset
115                               (if lsb0? (- mask-len 1) 0) ; start
116                               mask-len ; length
117                               mask-len ; word-length
118                               lsb0?)))
119     (apply +
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)))
123            )
124     )
125 )
126 \f
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).
133
134 (define (-ifmt-search-key insn sorted-ifld-list)
135   (string-map (lambda (ifld)
136                 (string-append " ("
137                                (or (obj-attr-value insn 'sanitize)
138                                    "-nosan-")
139                                " "
140                                (obj:name ifld)
141                                " "
142                                (ifld-ilk ifld)
143                                ")"))
144               sorted-ifld-list)
145 )
146
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.
151
152 (define (ifmt-build insn index search-key iflds)
153   (make <iformat>
154     (symbol-append 'ifmt- (obj:name insn))
155     (string-append "e.g. " (insn-syntax insn))
156     atlist-empty
157     index
158     search-key
159     iflds
160     (compute-insn-base-mask-length iflds)
161     (compute-insn-length iflds)
162     (compute-insn-base-mask iflds)
163     insn)
164 )
165 \f
166 ; Sformats.
167
168 (define <sformat>
169   (class-make '<sformat>
170               '(<ident>)
171               ; From <ident>:
172               ; - NAME is derived from number.
173               ; - COMMENT is the assembler syntax of an example insn that
174               ;   uses the format.
175               '(
176                 ; Index into the sformat table.
177                 number
178
179                 ; Sort key, used to determine insns with identical formats.
180                 key
181
182                 ; Non-#f if insns with this format are cti insns.
183                 cti?
184
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
189                 ; sformat.
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.
198                 in-ops
199                 out-ops
200
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.
206                 length
207
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.
211                 iflds
212
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.
216                 eg-insn
217
218                 ; <sformat-argbuf> entry
219                 ; FIXME: Temporary location, to be moved elsewhere
220                 (sbuf . #f)
221                 )
222               nil)
223 )
224
225 ; Accessor fns.
226
227 (define-getters <sformat> sfmt
228   (number key cti? in-ops out-ops length iflds eg-insn sbuf)
229 )
230
231 (define-setters <sformat> sfmt (sbuf))
232
233 (method-make-make! <sformat>
234                    '(name comment attrs
235                      number key cti? in-ops out-ops length iflds eg-insn)
236 )
237 \f
238 ; Return the <sformat> search key for a sorted field list and semantic
239 ; operands.
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).
243 ;
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.
248 ;
249 ; We assume INSN's <iformat> has been recorded.
250 ;
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.
254
255 (define (-sfmt-search-key insn cti? sorted-used-iflds sem-in-ops sem-out-ops)
256   (let ((op-key (lambda (op)
257                   (string-append " ("
258                                  (or (obj-attr-value insn 'sanitize)
259                                      "-nosan-")
260                                  " "
261                                  (obj:name op)
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
266                                  ; thing to do.
267                                  (if (memory? (op:type op))
268                                      ""
269                                      (string-append " "
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
274                                  ; by this.
275                                  (if (op:cond? op) " cond" "")
276                                  ")")))
277         )
278     (list
279      cti?
280      (insn-length insn)
281      (string-map (lambda (ifld)
282                    (string-append " (" (obj:name ifld) " " (ifld-ilk ifld) ")"))
283                  sorted-used-iflds)
284      (string-map op-key
285                  sem-in-ops)
286      (string-map op-key
287                  sem-out-ops)
288      ))
289 )
290
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.
297 ;
298 ; We assume INSN's <iformat> has already been recorded.
299
300 (define (sfmt-build insn index search-key cti? in-ops out-ops sorted-used-iflds)
301   (make <sformat>
302     (symbol-append 'sfmt- (obj:name insn))
303     (string-append "e.g. " (insn-syntax insn))
304     atlist-empty
305     index
306     search-key
307     cti?
308     in-ops
309     out-ops
310     (insn-length insn)
311     sorted-used-iflds
312     insn)
313 )
314
315 ; Sort IFLDS by dependencies and then by starting bit number.
316
317 (define (-sfmt-order-iflds iflds)
318   (let ((up? 
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))
323       (cond ((null? iflds)
324              (append (sort-ifield-list independent up?)
325                      (sort-ifield-list dependent up?)))
326             ; FIXME: quick hack.
327             ((multi-ifield? (car iflds))
328              (loop independent (cons (car iflds) dependent) (cdr iflds)))
329             (else
330              (loop (cons (car iflds) independent) dependent (cdr iflds))))))
331 )
332
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.
337
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))
343                           obj:name)))
344       (-sfmt-order-iflds all-iflds)))
345 )
346 \f
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.
350
351 (define <fmt-desc>
352   (class-make '<fmt-desc>
353               nil
354               '(
355                 ; #t if insn is a cti insn
356                 cti?
357
358                 ; sorted list of insn's ifields
359                 iflds
360
361                 ; computed set of input/output operands
362                 in-ops out-ops
363
364                 ; set of ifields used by IN-OPS,OUT-OPS.
365                 used-iflds
366
367                 ; computed set of attributes
368                 attrs
369                 )
370               nil)
371 )
372
373 ; Accessors.
374
375 (define-getters <fmt-desc> -fmt-desc
376   (cti? iflds in-ops out-ops used-iflds attrs)
377 )
378
379 ; Compute an iformat descriptor used to build an <iformat> object for INSN.
380 ;
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.
387 ;
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.
393 ;
394 ; ??? We never traverse the semantics of virtual insns.
395
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
402                            ; no fields.
403                            ;(not (ifld-lsb0? (car (insn-iflds insn))))
404                            (not (current-arch-insn-lsb0?))
405                            )))
406
407     (if (null? sorted-ifields)
408
409         ; Field list is unspecified.
410         (list #f #f atlist-empty)
411
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
418                                               insn sems)
419                             (csem-make #f #f #f
420                                        (if (insn-semantics insn)
421                                            (semantic-attrs #f ; FIXME: context
422                                                            insn sems)
423                                            atlist-empty))))
424                )
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))
430                           (insn-cti? insn))))
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)
435                         #f)
436                     attrs)
437                   compiled-sems
438                   attrs)))))
439 )
440
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.
445
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))
450                            ifmt-list)))
451
452     (if ifmt
453
454         ; Format was found, use it.
455         (begin
456           (logit 3 "Using iformat " (number->string (ifmt-number ifmt)) ".\n")
457           (insn-set-ifmt! insn ifmt)
458           )
459
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))
467           )
468         ))
469
470   *UNSPECIFIED*
471 )
472
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.
477 ;
478 ; We assume INSN's <iformat> has already been recorded.
479
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))
487                            sfmt-list)))
488
489     (if sfmt
490
491         ; Format was found, use it.
492         (begin
493           (logit 3 "Using sformat " (number->string (sfmt-number sfmt)) ".\n")
494           (insn-set-sfmt! insn sfmt)
495           )
496
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))
507           )
508         ))
509
510   *UNSPECIFIED*
511 )
512 \f
513 ; Main entry point.
514
515 ; Given a list of insns, compute the set of instruction formats, semantic
516 ; formats, semantic attributes, and compiled semantics for each insn.
517 ;
518 ; The computed <iformat> object is stored in the `ifmt' field of each insn.
519 ;
520 ; Attributes derived from the semantic code are added to the insn's attributes,
521 ; but they don't override any prespecified values.
522 ;
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.
526 ;
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.
530 ;
531 ; The result is a list of two lists: the set of computed iformats, and the
532 ; set of computed sformats.
533 ;
534 ; *** This is the most expensive calculation in CGEN.   ***
535 ; *** (mainly because of the detailed semantic parsing) ***
536
537 (define (ifmt-compute! insn-list compute-sformat?)
538   (logit 2 "Computing instruction formats and analyzing semantics ...\n")
539
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.
543
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)
554                                                 (caddr sem-ops)))
555                 ))
556             insn-list)
557
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.
560
561   (let* ((empty-ifmt (make <iformat>
562                           'ifmt-empty
563                           "empty iformat for unspecified field list"
564                           atlist-empty ; attrs
565                           -1 ; number
566                           #f ; key
567                           nil ; fields
568                           0 ; mask-length
569                           0 ; length
570                           0 ; mask
571                           #f)) ; eg-insn
572          (empty-sfmt (make <sformat>
573                           'sfmt-empty
574                           "empty sformat for unspecified field list"
575                           atlist-empty ; attrs
576                           -1 ; number
577                           #f ; key
578                           #f ; cti?
579                           nil ; sem-in-ops
580                           nil ; sem-out-ops
581                           0 ; length
582                           nil ; used iflds
583                           #f)) ; eg-insn
584          (ifmt-list (list empty-ifmt))
585          (sfmt-list (list empty-sfmt))
586          )
587
588     (for-each (lambda (insn)
589                 (logit 3 "Processing format for " (obj:name insn) ": "
590                        (insn-syntax insn) " ...\n")
591
592                 (let ((fmt-desc (insn-fmt-desc insn)))
593
594                   (if fmt-desc
595
596                       (begin
597                         ; Must compute <iformat> before <sformat>, the latter
598                         ; needs the former.
599                         (-ifmt-lookup-ifmt! insn fmt-desc ifmt-list)
600                         (if compute-sformat?
601                             (-ifmt-lookup-sfmt! insn fmt-desc sfmt-list)))
602
603                       ; No field list present, use empty format.
604                       (begin
605                         (insn-set-ifmt! insn empty-ifmt)
606                         (if compute-sformat?
607                             (insn-set-sfmt! insn empty-sfmt))))))
608
609               (non-multi-insns insn-list))
610
611     ; Done.  Return the computed iformat and sformat lists.
612     (list ifmt-list sfmt-list)
613     )
614 )