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