0.pre7.38:
[sbcl.git] / src / compiler / disassem.lisp
1 ;;;; machine-independent disassembler
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
11
12 (in-package "SB!DISASSEM")
13 \f
14 ;;; types and defaults
15
16 (defconstant label-column-width 7)
17
18 (deftype text-width () '(integer 0 1000))
19 (deftype alignment () '(integer 0 64))
20 (deftype offset () '(signed-byte 24))
21 (deftype address () '(unsigned-byte 32))
22 (deftype length () '(unsigned-byte 24))
23 (deftype column () '(integer 0 1000))
24
25 (defconstant max-filtered-value-index 32)
26 (deftype filtered-value-index ()
27   `(integer 0 ,max-filtered-value-index))
28 (deftype filtered-value-vector ()
29   `(simple-array t (,max-filtered-value-index)))
30 \f
31 ;;;; disassembly parameters
32
33 ;;; instructions
34 (defvar *disassem-insts* (make-hash-table :test 'eq))
35 (declaim (type hash-table *disassem-insts*))
36
37 (defvar *disassem-inst-space* nil)
38 (declaim (type (or null inst-space) *disassem-inst-space*))
39
40 ;;; minimum alignment of instructions, in bytes
41 (defvar *disassem-inst-alignment-bytes* sb!vm:word-bytes)
42 (declaim (type alignment *disassem-inst-alignment-bytes*))
43
44 (defvar *disassem-location-column-width* 8)
45 (declaim (type text-width *disassem-location-column-width*))
46
47 ;;; the width of the column in which instruction-names are printed. A
48 ;;; value of zero gives the effect of not aligning the arguments at
49 ;;; all.
50 (defvar *disassem-opcode-column-width* 6)
51 (declaim (type text-width *disassem-opcode-column-width*))
52
53 (defvar *disassem-note-column* 45
54   #!+sb-doc
55   "The column in which end-of-line comments for notes are started.")
56
57 ;;; the old CMU CL code to set the CMU CL disassembly parameters
58 #|
59 (defmacro set-disassem-params (&rest args)
60   #!+sb-doc
61   "Specify global disassembler params. &KEY arguments include:
62
63   :INSTRUCTION-ALIGNMENT number
64       Minimum alignment of instructions, in bits.
65
66   :ADDRESS-SIZE number
67       Size of a machine address, in bits.
68
69   :OPCODE-COLUMN-WIDTH
70       Width of the column used for printing the opcode portion of the
71       instruction, or NIL to use the default."
72   (gen-preamble-form args))
73
74 (defun gen-preamble-form (args)
75   #!+sb-doc
76   "Generate a form to specify global disassembler params. See the
77   documentation for SET-DISASSEM-PARAMS for more info."
78   (destructuring-bind
79       (&key instruction-alignment
80             address-size
81             (opcode-column-width nil opcode-column-width-p))
82       args
83     `(progn
84        (eval-when (:compile-toplevel :execute)
85          ;; these are not in the params because they only exist at compile time
86          (defparameter ,(format-table-name) (make-hash-table))
87          (defparameter ,(arg-type-table-name) nil)
88          (defparameter ,(function-cache-name) (make-function-cache)))
89        (let ((params
90               (or sb!c:*backend-disassem-params*
91                   (setf sb!c:*backend-disassem-params* (make-params)))))
92          (declare (ignorable params))
93          ,(when instruction-alignment
94             `(setf (params-instruction-alignment params)
95                    (bits-to-bytes ,instruction-alignment)))
96          ,(when address-size
97             `(setf (params-location-column-width params)
98                    (* 2 ,address-size)))
99          ,(when opcode-column-width-p
100             `(setf (params-opcode-column-width params) ,opcode-column-width))
101          'disassem-params))))
102 |#
103 \f
104 ;;;; cached functions
105
106 (defstruct (function-cache (:copier nil))
107   (printers nil :type list)
108   (labellers nil :type list)
109   (prefilters nil :type list))
110
111 (defvar *disassem-function-cache* (make-function-cache))
112 (declaim (type function-cache *disassem-function-cache*))
113 \f
114 ;;;; A DCHUNK contains the bits we look at to decode an
115 ;;;; instruction.
116 ;;;; I tried to keep this abstract so that if using integers > the machine
117 ;;;; word size conses too much, it can be changed to use bit-vectors or
118 ;;;; something.
119 ;;;;
120 ;;;; KLUDGE: It's not clear that using bit-vectors would be any more efficient.
121 ;;;; Perhaps the abstraction could go away. -- WHN 19991124
122
123 #!-sb-fluid
124 (declaim (inline dchunk-or dchunk-and dchunk-clear dchunk-not
125                  dchunk-make-mask dchunk-make-field
126                  sap-ref-dchunk
127                  dchunk-extract
128                  dchunk=
129                  dchunk-count-bits))
130
131 (defconstant dchunk-bits 32)
132
133 (deftype dchunk ()
134   `(unsigned-byte ,dchunk-bits))
135 (deftype dchunk-index ()
136   `(integer 0 ,dchunk-bits))
137
138 (defconstant dchunk-zero 0)
139 (defconstant dchunk-one #xFFFFFFFF)
140
141 (defun dchunk-extract (from pos)
142   (declare (type dchunk from))
143   (the dchunk (ldb pos (the dchunk from))))
144
145 (defmacro dchunk-copy (x)
146   `(the dchunk ,x))
147
148 (defun dchunk-or (to from)
149   (declare (type dchunk to from))
150   (the dchunk (logior to from)))
151 (defun dchunk-and (to from)
152   (declare (type dchunk to from))
153   (the dchunk (logand to from)))
154 (defun dchunk-clear (to from)
155   (declare (type dchunk to from))
156   (the dchunk (logandc2 to from)))
157 (defun dchunk-not (from)
158   (declare (type dchunk from))
159   (the dchunk (logand dchunk-one (lognot from))))
160
161 (defmacro dchunk-andf (to from)
162   `(setf ,to (dchunk-and ,to ,from)))
163 (defmacro dchunk-orf (to from)
164   `(setf ,to (dchunk-or ,to ,from)))
165 (defmacro dchunk-clearf (to from)
166   `(setf ,to (dchunk-clear ,to ,from)))
167
168 (defun dchunk-make-mask (pos)
169   (the dchunk (mask-field pos -1)))
170 (defun dchunk-make-field (pos value)
171   (the dchunk (dpb value pos 0)))
172
173 (defmacro make-dchunk (value)
174   `(the dchunk ,value))
175
176 (defun sap-ref-dchunk (sap byte-offset byte-order)
177   (declare (type sb!sys:system-area-pointer sap)
178            (type offset byte-offset)
179            (optimize (speed 3) (safety 0)))
180   (the dchunk
181        (if (eq byte-order :big-endian)
182            (+ (ash (sb!sys:sap-ref-8 sap byte-offset) 24)
183               (ash (sb!sys:sap-ref-8 sap (+ 1 byte-offset)) 16)
184               (ash (sb!sys:sap-ref-8 sap (+ 2 byte-offset)) 8)
185               (sb!sys:sap-ref-8 sap (+ 3 byte-offset)))
186            (+ (sb!sys:sap-ref-8 sap byte-offset)
187               (ash (sb!sys:sap-ref-8 sap (+ 1 byte-offset)) 8)
188               (ash (sb!sys:sap-ref-8 sap (+ 2 byte-offset)) 16)
189               (ash (sb!sys:sap-ref-8 sap (+ 3 byte-offset)) 24)))))
190
191 (defun dchunk-corrected-extract (from pos unit-bits byte-order)
192   (declare (type dchunk from))
193   (if (eq byte-order :big-endian)
194       (ldb (byte (byte-size pos)
195                  (+ (byte-position pos) (- dchunk-bits unit-bits)))
196            (the dchunk from))
197       (ldb pos (the dchunk from))))
198
199 (defmacro dchunk-insertf (place pos value)
200   `(setf ,place (the dchunk (dpb ,value ,pos (the dchunk,place)))))
201
202 (defun dchunk= (x y)
203   (declare (type dchunk x y))
204   (= x y))
205 (defmacro dchunk-zerop (x)
206   `(dchunk= ,x dchunk-zero))
207
208 (defun dchunk-strict-superset-p (sup sub)
209   (and (zerop (logandc2 sub sup))
210        (not (zerop (logandc2 sup sub)))))
211
212 (defun dchunk-count-bits (x)
213   (declare (type dchunk x))
214   (logcount x))
215 \f
216 (defstruct (instruction (:conc-name inst-)
217                         (:constructor
218                          make-instruction (name
219                                            format-name
220                                            print-name
221                                            length
222                                            mask id
223                                            printer
224                                            labeller prefilter control))
225                         (:copier nil))
226   (name nil :type (or symbol string))
227   (format-name nil :type (or symbol string))
228
229   (mask dchunk-zero :type dchunk)       ; bits in the inst that are constant
230   (id dchunk-zero :type dchunk)         ; value of those constant bits
231
232   (length 0 :type length)               ; in bytes
233
234   (print-name nil :type symbol)
235
236   ;; disassembly functions
237   (prefilter nil :type (or null function))
238   (labeller nil :type (or null function))
239   (printer (required-argument) :type (or null function))
240   (control nil :type (or null function))
241
242   ;; instructions that are the same as this instruction but with more
243   ;; constraints
244   (specializers nil :type list))
245 (def!method print-object ((inst instruction) stream)
246   (print-unreadable-object (inst stream :type t :identity t)
247     (format stream "~A(~A)" (inst-name inst) (inst-format-name inst))))
248 \f
249 ;;;; an instruction space holds all known machine instructions in a
250 ;;;; form that can be easily searched
251
252 (defstruct (inst-space (:conc-name ispace-)
253                        (:copier nil))
254   (valid-mask dchunk-zero :type dchunk) ; applies to *children*
255   (choices nil :type list))
256 (def!method print-object ((ispace inst-space) stream)
257   (print-unreadable-object (ispace stream :type t :identity t)))
258
259 (defstruct (inst-space-choice (:conc-name ischoice-)
260                               (:copier nil))
261   (common-id dchunk-zero :type dchunk)  ; applies to *parent's* mask
262   (subspace (required-argument) :type (or inst-space instruction)))
263 \f
264 ;;;; These are the kind of values we can compute for an argument, and
265 ;;;; how to compute them. The :CHECKER functions make sure that a given
266 ;;;; argument is compatible with another argument for a given use.
267
268 (defvar *arg-form-kinds* nil)
269
270 (defstruct (arg-form-kind (:copier nil))
271   (names nil :type list)
272   (producer (required-argument) :type function)
273   (checker (required-argument) :type function))
274
275 (defun arg-form-kind-or-lose (kind)
276   (or (getf *arg-form-kinds* kind)
277       (pd-error "unknown arg-form kind ~S" kind)))
278
279 (defun find-arg-form-producer (kind)
280   (arg-form-kind-producer (arg-form-kind-or-lose kind)))
281 (defun find-arg-form-checker (kind)
282   (arg-form-kind-checker (arg-form-kind-or-lose kind)))
283
284 (defun canonicalize-arg-form-kind (kind)
285   (car (arg-form-kind-names (arg-form-kind-or-lose kind))))
286 \f
287 ;;;; only used during compilation of the instructions for a backend
288 ;;;;
289 ;;;; FIXME: If only used then, isn't there some way we could do
290 ;;;; EVAL-WHEN tricks to keep this stuff from appearing in the target
291 ;;;; system?
292
293 (defvar *disassem-inst-formats* (make-hash-table))
294 (defvar *disassem-arg-types* nil)
295 (defvar *disassem-function-cache* (make-function-cache))
296
297 (defstruct (argument (:conc-name arg-)
298                      (:copier nil))
299   (name nil :type symbol)
300   (fields nil :type list)
301
302   (value nil :type (or list integer))
303   (sign-extend-p nil :type (member t nil))
304
305   ;; position in a vector of prefiltered values
306   (position 0 :type fixnum)
307
308   ;; functions to use
309   (printer nil)
310   (prefilter nil)
311   (use-label nil))
312
313 (defstruct (instruction-format (:conc-name format-)
314                                (:copier nil))
315   (name nil)
316   (args nil :type list)
317
318   (length 0 :type length)               ; in bytes
319
320   (default-printer nil :type list))
321 \f
322 ;;; A FUNSTATE holds the state of any arguments used in a disassembly
323 ;;; function.
324 (defstruct (funstate (:conc-name funstate-)
325                      (:constructor %make-funstate)
326                      (:copier nil))
327   (args nil :type list)
328   (arg-temps nil :type list))           ; See below.
329
330 (defun make-funstate (args)
331   ;; give the args a position
332   (let ((i 0))
333     (dolist (arg args)
334       (setf (arg-position arg) i)
335       (incf i)))
336   (%make-funstate :args args))
337
338 (defun funstate-compatible-p (funstate args)
339   (every #'(lambda (this-arg-temps)
340              (let* ((old-arg (car this-arg-temps))
341                     (new-arg (find (arg-name old-arg) args :key #'arg-name)))
342                (and new-arg
343                     (every #'(lambda (this-kind-temps)
344                                (funcall (find-arg-form-checker
345                                          (car this-kind-temps))
346                                         new-arg
347                                         old-arg))
348                            (cdr this-arg-temps)))))
349          (funstate-arg-temps funstate)))
350
351 (defun arg-or-lose (name funstate)
352   (let ((arg (find name (funstate-args funstate) :key #'arg-name)))
353     (when (null arg)
354       (pd-error "unknown argument ~S" name))
355     arg))
356 \f
357 ;;;; Since we can't include some values in compiled output as they are
358 ;;;; (notably functions), we sometimes use a VALSRC structure to keep
359 ;;;; track of the source from which they were derived.
360
361 (defstruct (valsrc (:constructor %make-valsrc)
362                    (:copier nil))
363   (value nil)
364   (source nil))
365
366 (defun make-valsrc (value source)
367   (cond ((equal value source)
368          source)
369         ((and (listp value) (eq (car value) 'function))
370          value)
371         (t
372          (%make-valsrc :value value :source source))))
373
374 ;;; machinery to provide more meaningful error messages during compilation
375 (defvar *current-instruction-flavor* nil)
376 (defun pd-error (fmt &rest args)
377   (if *current-instruction-flavor*
378       (error "~@<in printer-definition for ~S(~S): ~3I~:_~?~:>"
379              (car *current-instruction-flavor*)
380              (cdr *current-instruction-flavor*)
381              fmt args)
382       (apply #'error fmt args)))
383
384 ;;; FIXME:
385 ;;;  1. This should become a utility in SB!INT.
386 ;;;  2. Arrays and structures and maybe other things are
387 ;;;     self-evaluating too.
388 (defun self-evaluating-p (x)
389   (typecase x
390     (null t)
391     (keyword t)
392     (symbol (eq x t))
393     (cons nil)
394     (t t)))
395
396 (defun maybe-quote (evalp form)
397   (if (or evalp (self-evaluating-p form)) form `',form))
398
399 ;;; Detect things that obviously don't need wrapping, like
400 ;;; variable-refs and #'function.
401 (defun doesnt-need-wrapping-p (form)
402   (or (symbolp form)
403       (and (listp form)
404            (eq (car form) 'function)
405            (symbolp (cadr form)))))
406
407 (defun make-wrapper (form arg-name funargs prefix)
408   (if (and (listp form)
409            (eq (car form) 'function))
410       ;; a function def
411       (let ((wrapper-name (symbolicate prefix "-" arg-name "-WRAPPER"))
412             (wrapper-args (make-gensym-list (length funargs))))
413         (values `#',wrapper-name
414                 `(defun ,wrapper-name ,wrapper-args
415                    (funcall ,form ,@wrapper-args))))
416       ;; something else
417       (let ((wrapper-name (symbolicate "*" prefix "-" arg-name "-WRAPPER*")))
418         (values wrapper-name `(defparameter ,wrapper-name ,form)))))
419
420 (defun filter-overrides (overrides evalp)
421   (mapcar #'(lambda (override)
422               (list* (car override) (cadr override)
423                      (munge-fun-refs (cddr override) evalp)))
424           overrides))
425
426 (defparameter *arg-function-params*
427   '((:printer . (value stream dstate))
428     (:use-label . (value dstate))
429     (:prefilter . (value dstate))))
430
431 (defun munge-fun-refs (params evalp &optional wrap-defs-p (prefix ""))
432   (let ((params (copy-list params)))
433     (do ((tail params (cdr tail))
434          (wrapper-defs nil))
435         ((null tail)
436          (values params (nreverse wrapper-defs)))
437       (let ((fun-arg (assoc (car tail) *arg-function-params*)))
438         (when fun-arg
439           (let* ((fun-form (cadr tail))
440                  (quoted-fun-form `',fun-form))
441             (when (and wrap-defs-p (not (doesnt-need-wrapping-p fun-form)))
442               (multiple-value-bind (access-form wrapper-def-form)
443                   (make-wrapper fun-form (car fun-arg) (cdr fun-arg) prefix)
444                 (setf quoted-fun-form `',access-form)
445                 (push wrapper-def-form wrapper-defs)))
446             (if evalp
447                 (setf (cadr tail)
448                       `(make-valsrc ,fun-form ,quoted-fun-form))
449                 (setf (cadr tail)
450                       fun-form))))))))
451
452 (defun gen-args-def-form (overrides format-form &optional (evalp t))
453   (let ((args-var (gensym)))
454     `(let ((,args-var (copy-list (format-args ,format-form))))
455        ,@(mapcar #'(lambda (override)
456                      (update-args-form args-var
457                                        `',(car override)
458                                        (and (cdr override)
459                                             (cons :value (cdr override)))
460                                        evalp))
461                  overrides)
462        ,args-var)))
463
464 (defun gen-printer-def-forms-def-form (base-name
465                                        uniquified-name
466                                        def
467                                        &optional
468                                        (evalp t))
469   (declare (type symbol base-name))
470   (declare (type (or symbol string) uniquified-name))
471   (destructuring-bind
472       (format-name
473        (&rest field-defs)
474        &optional (printer-form :default)
475        &key ((:print-name print-name-form) `',base-name) control)
476       def
477     (let ((format-var (gensym))
478           (field-defs (filter-overrides field-defs evalp)))
479       `(let* ((*current-instruction-flavor* ',(cons base-name format-name))
480               (,format-var (format-or-lose ',format-name))
481               (args ,(gen-args-def-form field-defs format-var evalp))
482               (funcache *disassem-function-cache*))
483          ;; FIXME: This should be SPEED 0 but can't be until we support
484          ;; byte compilation of components of the SBCL system.
485          ;;(declare (optimize (speed 0) (safety 0) (debug 0)))
486          (multiple-value-bind (printer-fun printer-defun)
487              (find-printer-fun ',uniquified-name
488                                ',format-name
489                                ,(if (eq printer-form :default)
490                                      `(format-default-printer ,format-var)
491                                      (maybe-quote evalp printer-form))
492                                args funcache)
493            (multiple-value-bind (labeller-fun labeller-defun)
494                (find-labeller-fun ',uniquified-name args funcache)
495              (multiple-value-bind (prefilter-fun prefilter-defun)
496                  (find-prefilter-fun ',uniquified-name
497                                      ',format-name
498                                      args
499                                      funcache)
500                (multiple-value-bind (mask id)
501                    (compute-mask-id args)
502                  (values
503                   `(make-instruction ',',base-name
504                                      ',',format-name
505                                      ,',print-name-form
506                                      ,(format-length ,format-var)
507                                      ,mask
508                                      ,id
509                                      ,(and printer-fun `#',printer-fun)
510                                      ,(and labeller-fun `#',labeller-fun)
511                                      ,(and prefilter-fun `#',prefilter-fun)
512                                      ,',control)
513                   `(progn
514                      ,@(and printer-defun (list printer-defun))
515                      ,@(and labeller-defun (list labeller-defun))
516                      ,@(and prefilter-defun (list prefilter-defun))))
517                  ))))))))
518
519 (defun update-args-form (var name-form descrip-forms evalp
520                              &optional format-length-form)
521   `(setf ,var
522          ,(if evalp
523               `(modify-or-add-arg ,name-form
524                                   ,var
525                                   *disassem-arg-types*
526                                   ,@(and format-length-form
527                                          `(:format-length
528                                             ,format-length-form))
529                                   ,@descrip-forms)
530               `(apply #'modify-or-add-arg
531                       ,name-form
532                       ,var
533                       *disassem-arg-types*
534                       ,@(and format-length-form
535                              `(:format-length ,format-length-form))
536                       ',descrip-forms))))
537
538 (defun format-or-lose (name)
539   (or (gethash name *disassem-inst-formats*)
540       (pd-error "unknown instruction format ~S" name)))
541
542 ;;; FIXME: needed only at build-the-system time, not in running system
543 (defmacro define-instruction-format (header &rest fields)
544   #!+sb-doc
545   "DEFINE-INSTRUCTION-FORMAT (Name Length {Format-Key Value}*) Arg-Def*
546   Define an instruction format NAME for the disassembler's use. LENGTH is
547   the length of the format in bits.
548   Possible FORMAT-KEYs:
549
550   :INCLUDE other-format-name
551       Inherit all arguments and properties of the given format. Any
552       arguments defined in the current format definition will either modify
553       the copy of an existing argument (keeping in the same order with
554       respect to when pre-filter's are called), if it has the same name as
555       one, or be added to the end.
556   :DEFAULT-PRINTER printer-list
557       Use the given PRINTER-LIST as a format to print any instructions of
558       this format when they don't specify something else.
559
560   Each ARG-DEF defines one argument in the format, and is of the form
561     (Arg-Name {Arg-Key Value}*)
562
563   Possible ARG-KEYs (the values are evaluated unless otherwise specified):
564
565   :FIELDS byte-spec-list
566       The argument takes values from these fields in the instruction. If
567       the list is of length one, then the corresponding value is supplied by
568       itself; otherwise it is a list of the values. The list may be NIL.
569   :FIELD byte-spec
570       The same as :FIELDS (list byte-spec).
571
572   :VALUE value
573       If the argument only has one field, this is the value it should have,
574       otherwise it's a list of the values of the individual fields. This can
575       be overridden in an instruction-definition or a format definition
576       including this one by specifying another, or NIL to indicate that it's
577       variable.
578
579   :SIGN-EXTEND boolean
580       If non-NIL, the raw value of this argument is sign-extended,
581       immediately after being extracted from the instruction (before any
582       prefilters are run, for instance). If the argument has multiple
583       fields, they are all sign-extended.
584
585   :TYPE arg-type-name
586       Inherit any properties of the given argument-type.
587
588   :PREFILTER function
589       A function which is called (along with all other prefilters, in the
590       order that their arguments appear in the instruction-format) before
591       any printing is done, to filter the raw value. Any uses of READ-SUFFIX
592       must be done inside a prefilter.
593
594   :PRINTER function-string-or-vector
595       A function, string, or vector which is used to print this argument.
596
597   :USE-LABEL
598       If non-NIL, the value of this argument is used as an address, and if
599       that address occurs inside the disassembled code, it is replaced by a
600       label. If this is a function, it is called to filter the value."
601   (gen-format-def-form header fields))
602
603 ;;; FIXME: needed only at build-the-system time, not in running system
604 (defun gen-format-def-form (header descrips &optional (evalp t))
605   #!+sb-doc
606   "Generate a form to define an instruction format. See
607   DEFINE-INSTRUCTION-FORMAT for more info."
608   (when (atom header)
609     (setf header (list header)))
610   (destructuring-bind (name length &key default-printer include) header
611     (let ((args-var (gensym))
612           (length-var (gensym))
613           (all-wrapper-defs nil)
614           (arg-count 0))
615       (collect ((arg-def-forms))
616         (dolist (descrip descrips)
617           (let ((name (pop descrip)))
618             (multiple-value-bind (descrip wrapper-defs)
619                 (munge-fun-refs
620                  descrip evalp t (format nil "~:@(~A~)-~D" name arg-count))
621               (arg-def-forms
622                (update-args-form args-var `',name descrip evalp length-var))
623               (setf all-wrapper-defs
624                     (nconc wrapper-defs all-wrapper-defs)))
625             (incf arg-count)))
626         `(progn
627            ,@all-wrapper-defs
628            (eval-when (:compile-toplevel :execute)
629              (let ((,length-var ,length)
630                    (,args-var
631                     ,(and include
632                           `(copy-list
633                             (format-args
634                              (format-or-lose ,include))))))
635                ,@(arg-def-forms)
636                (setf (gethash ',name *disassem-inst-formats*)
637                      (make-instruction-format
638                       :name ',name
639                       :length (bits-to-bytes ,length-var)
640                       :default-printer ,(maybe-quote evalp default-printer)
641                       :args ,args-var))
642                (eval
643                 `(progn
644                    ,@(mapcar #'(lambda (arg)
645                                  (when (arg-fields arg)
646                                    (gen-arg-access-macro-def-form
647                                     arg ,args-var ',name)))
648                              ,args-var))))))))))
649
650 ;;; FIXME: probably needed only at build-the-system time, not in
651 ;;; final target system
652 (defun modify-or-add-arg (arg-name
653                           args
654                           type-table
655                           &key
656                           (value nil value-p)
657                           (type nil type-p)
658                           (prefilter nil prefilter-p)
659                           (printer nil printer-p)
660                           (sign-extend nil sign-extend-p)
661                           (use-label nil use-label-p)
662                           (field nil field-p)
663                           (fields nil fields-p)
664                           format-length)
665   (let* ((arg-pos (position arg-name args :key #'arg-name))
666          (arg
667           (if (null arg-pos)
668               (let ((arg (make-argument :name arg-name)))
669                 (if (null args)
670                     (setf args (list arg))
671                     (push arg (cdr (last args))))
672                 arg)
673               (setf (nth arg-pos args)
674                     (copy-structure (nth arg-pos args))))))
675     (when (and field-p (not fields-p))
676       (setf fields (list field))
677       (setf fields-p t))
678     (when type-p
679       (set-arg-from-type arg type type-table))
680     (when value-p
681       (setf (arg-value arg) value))
682     (when prefilter-p
683       (setf (arg-prefilter arg) prefilter))
684     (when sign-extend-p
685       (setf (arg-sign-extend-p arg) sign-extend))
686     (when printer-p
687       (setf (arg-printer arg) printer))
688     (when use-label-p
689       (setf (arg-use-label arg) use-label))
690     (when fields-p
691       (when (null format-length)
692         (error
693          "~@<in arg ~S: ~3I~:_~
694           can't specify fields except using DEFINE-INSTRUCTION-FORMAT~:>"
695          arg-name))
696       (setf (arg-fields arg)
697             (mapcar #'(lambda (bytespec)
698                         (when (> (+ (byte-position bytespec)
699                                     (byte-size bytespec))
700                                  format-length)
701                           (error "~@<in arg ~S: ~3I~:_~
702                                      The field ~S doesn't fit in an ~
703                                      instruction-format ~D bits wide.~:>"
704                                  arg-name
705                                  bytespec
706                                  format-length))
707                         (correct-dchunk-bytespec-for-endianness
708                          bytespec
709                          format-length
710                          sb!c:*backend-byte-order*))
711                     fields)))
712     args))
713
714 (defun gen-arg-access-macro-def-form (arg args format-name)
715   (let* ((funstate (make-funstate args))
716          (arg-val-form (arg-value-form arg funstate :adjusted))
717          (bindings (make-arg-temp-bindings funstate)))
718     `(sb!xc:defmacro ,(symbolicate format-name "-" (arg-name arg))
719          (chunk dstate)
720        `(let ((chunk ,chunk) (dstate ,dstate))
721           (declare (ignorable chunk dstate))
722           (flet ((local-filtered-value (offset)
723                    (declare (type filtered-value-index offset))
724                    (aref (dstate-filtered-values dstate) offset))
725                  (local-extract (bytespec)
726                    (dchunk-extract chunk bytespec)))
727             (declare (ignorable #'local-filtered-value #'local-extract)
728                      (inline local-filtered-value local-extract))
729             (let* ,',bindings
730               ,',arg-val-form))))))
731
732 (defun arg-value-form (arg funstate
733                        &optional
734                        (kind :final)
735                        (allow-multiple-p (not (eq kind :numeric))))
736   (let ((forms (gen-arg-forms arg kind funstate)))
737     (when (and (not allow-multiple-p)
738                (listp forms)
739                (/= (length forms) 1))
740       (pd-error "~S must not have multiple values." arg))
741     (maybe-listify forms)))
742
743 (defun correct-dchunk-bytespec-for-endianness (bs unit-bits byte-order)
744   (if (eq byte-order :big-endian)
745       (byte (byte-size bs) (+ (byte-position bs) (- dchunk-bits unit-bits)))
746       bs))
747
748 (defun make-arg-temp-bindings (funstate)
749   ;; (Everything is in reverse order, so we just use PUSH, which
750   ;; results in everything being in the right order at the end.)
751   (let ((bindings nil))
752     (dolist (ats (funstate-arg-temps funstate))
753       (dolist (atk (cdr ats))
754         (cond ((null (cadr atk)))
755               ((atom (cadr atk))
756                (push `(,(cadr atk) ,(cddr atk)) bindings))
757               (t
758                (mapc #'(lambda (var form)
759                          (push `(,var ,form) bindings))
760                      (cadr atk)
761                      (cddr atk))))))
762     bindings))
763
764 (defun gen-arg-forms (arg kind funstate)
765   (multiple-value-bind (vars forms)
766       (get-arg-temp arg kind funstate)
767     (when (null forms)
768       (multiple-value-bind (new-forms single-value-p)
769           (funcall (find-arg-form-producer kind) arg funstate)
770         (setq forms new-forms)
771         (cond ((or single-value-p (atom forms))
772                (unless (symbolp forms)
773                  (setq vars (gensym))))
774               ((every #'symbolp forms)
775                ;; just use the same as the forms
776                (setq vars nil))
777               (t
778                (setq vars (make-gensym-list (length forms)))))
779         (set-arg-temps vars forms arg kind funstate)))
780     (or vars forms)))
781
782 (defun maybe-listify (forms)
783   (cond ((atom forms)
784          forms)
785         ((/= (length forms) 1)
786          `(list ,@forms))
787         (t
788          (car forms))))
789 \f
790 (defun set-arg-from-type (arg type-name table)
791   (let ((type-arg (find type-name table :key #'arg-name)))
792     (when (null type-arg)
793       (pd-error "unknown argument type: ~S" type-name))
794     (setf (arg-printer arg) (arg-printer type-arg))
795     (setf (arg-prefilter arg) (arg-prefilter type-arg))
796     (setf (arg-sign-extend-p arg) (arg-sign-extend-p type-arg))
797     (setf (arg-use-label arg) (arg-use-label type-arg))))
798
799 (defun get-arg-temp (arg kind funstate)
800   (let ((this-arg-temps (assoc arg (funstate-arg-temps funstate))))
801     (if this-arg-temps
802         (let ((this-kind-temps
803                (assoc (canonicalize-arg-form-kind kind)
804                       (cdr this-arg-temps))))
805           (values (cadr this-kind-temps) (cddr this-kind-temps)))
806         (values nil nil))))
807
808 (defun set-arg-temps (vars forms arg kind funstate)
809   (let ((this-arg-temps
810          (or (assoc arg (funstate-arg-temps funstate))
811              (car (push (cons arg nil) (funstate-arg-temps funstate)))))
812         (kind (canonicalize-arg-form-kind kind)))
813     (let ((this-kind-temps
814            (or (assoc kind (cdr this-arg-temps))
815                (car (push (cons kind nil) (cdr this-arg-temps))))))
816       (setf (cdr this-kind-temps) (cons vars forms)))))
817 \f
818 (defmacro define-argument-type (name &rest args)
819   #!+sb-doc
820   "DEFINE-ARGUMENT-TYPE Name {Key Value}*
821   Define a disassembler argument type NAME (which can then be referenced in
822   another argument definition using the :TYPE argument). &KEY args are:
823
824   :SIGN-EXTEND boolean
825       If non-NIL, the raw value of this argument is sign-extended.
826
827   :TYPE arg-type-name
828       Inherit any properties of given argument-type.
829
830   :PREFILTER function
831       A function which is called (along with all other prefilters, in the
832       order that their arguments appear in the instruction- format) before
833       any printing is done, to filter the raw value. Any uses of READ-SUFFIX
834       must be done inside a prefilter.
835
836   :PRINTER function-string-or-vector
837       A function, string, or vector which is used to print an argument of
838       this type.
839
840   :USE-LABEL
841       If non-NIL, the value of an argument of this type is used as an
842       address, and if that address occurs inside the disassembled code, it is
843       replaced by a label. If this is a function, it is called to filter the
844       value."
845   (gen-arg-type-def-form name args))
846
847 (defun gen-arg-type-def-form (name args &optional (evalp t))
848   #!+sb-doc
849   "Generate a form to define a disassembler argument type. See
850   DEFINE-ARGUMENT-TYPE for more info."
851   (multiple-value-bind (args wrapper-defs)
852       (munge-fun-refs args evalp t name)
853     `(progn
854        ,@wrapper-defs
855        (eval-when (:compile-toplevel :execute)
856          ,(update-args-form '*disassem-arg-types* `',name args evalp))
857        ',name)))
858 \f
859 (defmacro def-arg-form-kind ((&rest names) &rest inits)
860   `(let ((kind (make-arg-form-kind :names ',names ,@inits)))
861      ,@(mapcar #'(lambda (name)
862                    `(setf (getf *arg-form-kinds* ',name) kind))
863                names)))
864
865 (def-arg-form-kind (:raw)
866   :producer #'(lambda (arg funstate)
867                 (declare (ignore funstate))
868                 (mapcar #'(lambda (bytespec)
869                             `(the (unsigned-byte ,(byte-size bytespec))
870                                   (local-extract ',bytespec)))
871                         (arg-fields arg)))
872   :checker #'(lambda (new-arg old-arg)
873                (equal (arg-fields new-arg)
874                       (arg-fields old-arg))))
875
876 (def-arg-form-kind (:sign-extended :unfiltered)
877   :producer #'(lambda (arg funstate)
878                 (let ((raw-forms (gen-arg-forms arg :raw funstate)))
879                   (if (and (arg-sign-extend-p arg) (listp raw-forms))
880                       (mapcar #'(lambda (form field)
881                                   `(the (signed-byte ,(byte-size field))
882                                         (sign-extend ,form
883                                                      ,(byte-size field))))
884                               raw-forms
885                               (arg-fields arg))
886                       raw-forms)))
887   :checker #'(lambda (new-arg old-arg)
888                (equal (arg-sign-extend-p new-arg)
889                       (arg-sign-extend-p old-arg))))
890
891 (defun valsrc-equal (f1 f2)
892   (if (null f1)
893       (null f2)
894       (equal (value-or-source f1)
895              (value-or-source f2))))
896
897 (def-arg-form-kind (:filtering)
898   :producer #'(lambda (arg funstate)
899                 (let ((sign-extended-forms
900                        (gen-arg-forms arg :sign-extended funstate))
901                       (pf (arg-prefilter arg)))
902                   (if pf
903                       (values
904                        `(local-filter ,(maybe-listify sign-extended-forms)
905                                       ,(source-form pf))
906                        t)
907                       (values sign-extended-forms nil))))
908   :checker #'(lambda (new-arg old-arg)
909                (valsrc-equal (arg-prefilter new-arg) (arg-prefilter old-arg))))
910
911 (def-arg-form-kind (:filtered :unadjusted)
912   :producer #'(lambda (arg funstate)
913                 (let ((pf (arg-prefilter arg)))
914                   (if pf
915                       (values `(local-filtered-value ,(arg-position arg)) t)
916                       (gen-arg-forms arg :sign-extended funstate))))
917   :checker #'(lambda (new-arg old-arg)
918                (let ((pf1 (arg-prefilter new-arg))
919                      (pf2 (arg-prefilter old-arg)))
920                  (if (null pf1)
921                      (null pf2)
922                      (= (arg-position new-arg)
923                         (arg-position old-arg))))))
924
925 (def-arg-form-kind (:adjusted :numeric :unlabelled)
926   :producer #'(lambda (arg funstate)
927                 (let ((filtered-forms (gen-arg-forms arg :filtered funstate))
928                       (use-label (arg-use-label arg)))
929                   (if (and use-label (not (eq use-label t)))
930                       (list
931                        `(adjust-label ,(maybe-listify filtered-forms)
932                                       ,(source-form use-label)))
933                       filtered-forms)))
934   :checker #'(lambda (new-arg old-arg)
935                (valsrc-equal (arg-use-label new-arg) (arg-use-label old-arg))))
936
937 (def-arg-form-kind (:labelled :final)
938   :producer #'(lambda (arg funstate)
939                 (let ((adjusted-forms
940                        (gen-arg-forms arg :adjusted funstate))
941                       (use-label (arg-use-label arg)))
942                   (if use-label
943                       (let ((form (maybe-listify adjusted-forms)))
944                         (if (and (not (eq use-label t))
945                                  (not (atom adjusted-forms))
946                                  (/= (Length adjusted-forms) 1))
947                             (pd-error
948                              "cannot label a multiple-field argument ~
949                               unless using a function: ~S" arg)
950                             `((lookup-label ,form))))
951                       adjusted-forms)))
952   :checker #'(lambda (new-arg old-arg)
953                (let ((lf1 (arg-use-label new-arg))
954                      (lf2 (arg-use-label old-arg)))
955                  (if (null lf1) (null lf2) t))))
956
957 ;;; This is a bogus kind that's just used to ensure that printers are
958 ;;; compatible...
959 (def-arg-form-kind (:printed)
960   :producer #'(lambda (&rest noise)
961                 (declare (ignore noise))
962                 (pd-error "bogus! can't use the :printed value of an arg!"))
963   :checker #'(lambda (new-arg old-arg)
964                (valsrc-equal (arg-printer new-arg) (arg-printer old-arg))))
965
966 (defun remember-printer-use (arg funstate)
967   (set-arg-temps nil nil arg :printed funstate))
968 \f
969 ;;; Returns a version of THING suitable for including in an evaluable
970 ;;; position in some form.
971 (defun source-form (thing)
972   (cond ((valsrc-p thing)
973          (valsrc-source thing))
974         ((functionp thing)
975          (pd-error
976           "can't dump functions, so function ref form must be quoted: ~S"
977           thing))
978         ((self-evaluating-p thing)
979          thing)
980         ((eq (car thing) 'function)
981          thing)
982         (t
983          `',thing)))
984
985 ;;; Return anything but a VALSRC structure.
986 (defun value-or-source (thing)
987   (if (valsrc-p thing)
988       (valsrc-value thing)
989       thing))
990 \f
991 (defstruct (cached-function (:conc-name cached-fun-)
992                             (:copier nil))
993   (funstate nil :type (or null funstate))
994   (constraint nil :type list)
995   (name nil :type (or null symbol)))
996
997 (defun find-cached-function (cached-funs args constraint)
998   (dolist (cached-fun cached-funs nil)
999     (let ((funstate (cached-fun-funstate cached-fun)))
1000       (when (and (equal constraint (cached-fun-constraint cached-fun))
1001                  (or (null funstate)
1002                      (funstate-compatible-p funstate args)))
1003         (return cached-fun)))))
1004
1005 (defmacro !with-cached-function ((name-var
1006                                   funstate-var
1007                                   cache
1008                                   cache-slot
1009                                   args
1010                                   &key
1011                                   constraint
1012                                   (stem (required-argument)))
1013                                  &body defun-maker-forms)
1014   (let ((cache-var (gensym))
1015         (constraint-var (gensym)))
1016     `(let* ((,constraint-var ,constraint)
1017             (,cache-var (find-cached-function (,cache-slot ,cache)
1018                                               ,args ,constraint-var)))
1019        (cond (,cache-var
1020               (values (cached-fun-name ,cache-var) nil))
1021              (t
1022               (let* ((,name-var (symbolicate "CACHED-FUN--" ,stem))
1023                      (,funstate-var (make-funstate ,args))
1024                      (,cache-var
1025                       (make-cached-function :name ,name-var
1026                                             :funstate ,funstate-var
1027                                             :constraint ,constraint-var)))
1028                 (values ,name-var
1029                         `(progn
1030                            ,(progn ,@defun-maker-forms)
1031                            (eval-when (:compile-toplevel :execute)
1032                              (push ,,cache-var
1033                                    (,',cache-slot ',,cache)))))))))))
1034 \f
1035 (defun find-printer-fun (%name %format-name printer-source args cache)
1036   (declare (type (or string symbol) %name))
1037   (if (null printer-source)
1038       (values nil nil)
1039       (let ((printer-source (preprocess-printer printer-source args)))
1040         (!with-cached-function
1041            (name funstate cache function-cache-printers args
1042                  :constraint printer-source
1043                  :stem (concatenate 'string
1044                                     (string %name)
1045                                     "-"
1046                                     (symbol-name %format-name)
1047                                     "-PRINTER"))
1048          (make-printer-defun printer-source funstate name)))))
1049 \f
1050 ;;;; Note that these things are compiled byte compiled to save space.
1051
1052 (defun make-printer-defun (source funstate function-name)
1053   (let ((printer-form (compile-printer-list source funstate))
1054         (bindings (make-arg-temp-bindings funstate)))
1055     `(defun ,function-name (chunk inst stream dstate)
1056        (declare (type dchunk chunk)
1057                 (type instruction inst)
1058                 (type stream stream)
1059                 (type disassem-state dstate)
1060                 ;; FIXME: This should be SPEED 0 but can't be until we support
1061                 ;; byte compilation of components of the SBCL system.
1062                 #+nil (optimize (speed 0) (safety 0) (debug 0)))
1063        (macrolet ((local-format-arg (arg fmt)
1064                     `(funcall (formatter ,fmt) stream ,arg)))
1065          (flet ((local-tab-to-arg-column ()
1066                   (tab (dstate-argument-column dstate) stream))
1067                 (local-print-name ()
1068                   (princ (inst-print-name inst) stream))
1069                 (local-write-char (ch)
1070                   (write-char ch stream))
1071                 (local-princ (thing)
1072                   (princ thing stream))
1073                 (local-princ16 (thing)
1074                   (princ16 thing stream))
1075                 (local-call-arg-printer (arg printer)
1076                   (funcall printer arg stream dstate))
1077                 (local-call-global-printer (fun)
1078                   (funcall fun chunk inst stream dstate))
1079                 (local-filtered-value (offset)
1080                   (declare (type filtered-value-index offset))
1081                   (aref (dstate-filtered-values dstate) offset))
1082                 (local-extract (bytespec)
1083                   (dchunk-extract chunk bytespec))
1084                 (lookup-label (lab)
1085                   (or (gethash lab (dstate-label-hash dstate))
1086                       lab))
1087                 (adjust-label (val adjust-fun)
1088                   (funcall adjust-fun val dstate)))
1089            (declare (ignorable #'local-tab-to-arg-column
1090                                #'local-print-name
1091                                #'local-princ #'local-princ16
1092                                #'local-write-char
1093                                #'local-call-arg-printer
1094                                #'local-call-global-printer
1095                                #'local-extract
1096                                #'local-filtered-value
1097                                #'lookup-label #'adjust-label)
1098                     (inline local-tab-to-arg-column
1099                             local-princ local-princ16
1100                             local-call-arg-printer local-call-global-printer
1101                             local-filtered-value local-extract
1102                             lookup-label adjust-label))
1103            (let* ,bindings
1104              ,@printer-form))))))
1105 \f
1106 (defun preprocess-test (subj form args)
1107   (multiple-value-bind (subj test)
1108       (if (and (consp form) (symbolp (car form)) (not (keywordp (car form))))
1109           (values (car form) (cdr form))
1110           (values subj form))
1111     (let ((key (if (consp test) (car test) test))
1112           (body (if (consp test) (cdr test) nil)))
1113       (case key
1114         (:constant
1115          (if (null body)
1116              ;; If no supplied constant values, just any constant is ok,
1117              ;; just see whether there's some constant value in the arg.
1118              (not
1119               (null
1120                (arg-value
1121                 (or (find subj args :key #'arg-name)
1122                     (pd-error "unknown argument ~S" subj)))))
1123              ;; Otherwise, defer to run-time.
1124              form))
1125         ((:or :and :not)
1126          (sharing-cons
1127           form
1128           subj
1129           (sharing-cons
1130            test
1131            key
1132            (sharing-mapcar
1133             #'(lambda (sub-test)
1134                 (preprocess-test subj sub-test args))
1135             body))))
1136         (t form)))))
1137
1138 (defun preprocess-conditionals (printer args)
1139   (if (atom printer)
1140       printer
1141       (case (car printer)
1142         (:unless
1143          (preprocess-conditionals
1144           `(:cond ((:not ,(nth 1 printer)) ,@(nthcdr 2 printer)))
1145           args))
1146         (:when
1147          (preprocess-conditionals `(:cond (,(cdr printer))) args))
1148         (:if
1149          (preprocess-conditionals
1150           `(:cond (,(nth 1 printer) ,(nth 2 printer))
1151                   (t ,(nth 3 printer)))
1152           args))
1153         (:cond
1154          (sharing-cons
1155           printer
1156           :cond
1157           (sharing-mapcar
1158            #'(lambda (clause)
1159                (let ((filtered-body
1160                       (sharing-mapcar
1161                        #'(lambda (sub-printer)
1162                            (preprocess-conditionals sub-printer args))
1163                        (cdr clause))))
1164                  (sharing-cons
1165                   clause
1166                   (preprocess-test (find-first-field-name filtered-body)
1167                                    (car clause)
1168                                    args)
1169                   filtered-body)))
1170            (cdr printer))))
1171         (quote printer)
1172         (t
1173          (sharing-mapcar
1174           #'(lambda (sub-printer)
1175               (preprocess-conditionals sub-printer args))
1176           printer)))))
1177
1178 (defun preprocess-printer (printer args)
1179   #!+sb-doc
1180   "Returns a version of the disassembly-template PRINTER with compile-time
1181   tests (e.g. :constant without a value), and any :CHOOSE operators resolved
1182   properly for the args ARGS. (:CHOOSE Sub*) simply returns the first Sub in
1183   which every field reference refers to a valid arg."
1184   (preprocess-conditionals (preprocess-chooses printer args) args))
1185 \f
1186 (defun find-first-field-name (tree)
1187   #!+sb-doc
1188   "Returns the first non-keyword symbol in a depth-first search of TREE."
1189   (cond ((null tree)
1190          nil)
1191         ((and (symbolp tree) (not (keywordp tree)))
1192          tree)
1193         ((atom tree)
1194          nil)
1195         ((eq (car tree) 'quote)
1196          nil)
1197         (t
1198          (or (find-first-field-name (car tree))
1199              (find-first-field-name (cdr tree))))))
1200
1201 (defun preprocess-chooses (printer args)
1202   (cond ((atom printer)
1203          printer)
1204         ((eq (car printer) :choose)
1205          (pick-printer-choice (cdr printer) args))
1206         (t
1207          (sharing-mapcar #'(lambda (sub) (preprocess-chooses sub args))
1208                          printer))))
1209 \f
1210 ;;;; some simple functions that help avoid consing when we're just
1211 ;;;; recursively filtering things that usually don't change
1212
1213 (defun sharing-cons (old-cons car cdr)
1214   #!+sb-doc
1215   "If CAR is eq to the car of OLD-CONS and CDR is eq to the CDR, return
1216   OLD-CONS, otherwise return (cons CAR CDR)."
1217   (if (and (eq car (car old-cons)) (eq cdr (cdr old-cons)))
1218       old-cons
1219       (cons car cdr)))
1220
1221 (defun sharing-mapcar (fun list)
1222   #!+sb-doc
1223   "A simple (one list arg) mapcar that avoids consing up a new list
1224   as long as the results of calling FUN on the elements of LIST are
1225   eq to the original."
1226   (and list
1227        (sharing-cons list
1228                      (funcall fun (car list))
1229                      (sharing-mapcar fun (cdr list)))))
1230 \f
1231 (defun all-arg-refs-relevant-p (printer args)
1232   (cond ((or (null printer) (keywordp printer) (eq printer t))
1233          t)
1234         ((symbolp printer)
1235          (find printer args :key #'arg-name))
1236         ((listp printer)
1237          (every #'(lambda (x) (all-arg-refs-relevant-p x args))
1238                 printer))
1239         (t t)))
1240
1241 (defun pick-printer-choice (choices args)
1242   (dolist (choice choices
1243            (pd-error "no suitable choice found in ~S" choices))
1244     (when (all-arg-refs-relevant-p choice args)
1245       (return choice))))
1246
1247 (defun compile-printer-list (sources funstate)
1248   (unless (null sources)
1249     ;; Coalesce adjacent symbols/strings, and convert to strings if possible,
1250     ;; since they require less consing to write.
1251     (do ((el (car sources) (car sources))
1252          (names nil (cons (strip-quote el) names)))
1253         ((not (string-or-qsym-p el))
1254          (when names
1255            ;; concatenate adjacent strings and symbols
1256            (let ((string
1257                   (apply #'concatenate
1258                          'string
1259                          (mapcar #'string (nreverse names)))))
1260              (push (if (some #'alpha-char-p string)
1261                        `',(make-symbol string) ; Preserve casifying output.
1262                        string)
1263                    sources))))
1264       (pop sources))
1265     (cons (compile-printer-body (car sources) funstate)
1266           (compile-printer-list (cdr sources) funstate))))
1267
1268 (defun compile-printer-body (source funstate)
1269   (cond ((null source)
1270          nil)
1271         ((eq source :name)
1272          `(local-print-name))
1273         ((eq source :tab)
1274          `(local-tab-to-arg-column))
1275         ((keywordp source)
1276          (pd-error "unknown printer element: ~S" source))
1277         ((symbolp source)
1278          (compile-print source funstate))
1279         ((atom source)
1280          `(local-princ ',source))
1281         ((eq (car source) :using)
1282          (unless (or (stringp (cadr source))
1283                      (and (listp (cadr source))
1284                           (eq (caadr source) 'function)))
1285            (pd-error "The first arg to :USING must be a string or #'function."))
1286          (compile-print (caddr source) funstate
1287                         (cons (eval (cadr source)) (cadr source))))
1288         ((eq (car source) :plus-integer)
1289          ;; prints the given field proceed with a + or a -
1290          (let ((form
1291                 (arg-value-form (arg-or-lose (cadr source) funstate)
1292                                 funstate
1293                                 :numeric)))
1294            `(progn
1295               (when (>= ,form 0)
1296                 (local-write-char #\+))
1297               (local-princ ,form))))
1298         ((eq (car source) 'quote)
1299          `(local-princ ,source))
1300         ((eq (car source) 'function)
1301          `(local-call-global-printer ,source))
1302         ((eq (car source) :cond)
1303          `(cond ,@(mapcar #'(lambda (clause)
1304                               `(,(compile-test (find-first-field-name
1305                                                 (cdr clause))
1306                                                (car clause)
1307                                                funstate)
1308                                 ,@(compile-printer-list (cdr clause)
1309                                                         funstate)))
1310                           (cdr source))))
1311         ;; :IF, :UNLESS, and :WHEN are replaced by :COND during preprocessing
1312         (t
1313          `(progn ,@(compile-printer-list source funstate)))))
1314
1315 (defun compile-print (arg-name funstate &optional printer)
1316   (let* ((arg (arg-or-lose arg-name funstate))
1317          (printer (or printer (arg-printer arg)))
1318          (printer-val (value-or-source printer))
1319          (printer-src (source-form printer)))
1320     (remember-printer-use arg funstate)
1321     (cond ((stringp printer-val)
1322            `(local-format-arg ,(arg-value-form arg funstate) ,printer-val))
1323           ((vectorp printer-val)
1324            `(local-princ
1325              (aref ,printer-src
1326                    ,(arg-value-form arg funstate :numeric))))
1327           ((or (functionp printer-val)
1328                (and (consp printer-val) (eq (car printer-val) 'function)))
1329            `(local-call-arg-printer ,(arg-value-form arg funstate)
1330                                     ,printer-src))
1331           ((or (null printer-val) (eq printer-val t))
1332            `(,(if (arg-use-label arg) 'local-princ16 'local-princ)
1333              ,(arg-value-form arg funstate)))
1334           (t
1335            (pd-error "illegal printer: ~S" printer-src)))))
1336
1337 (defun string-or-qsym-p (thing)
1338   (or (stringp thing)
1339       (and (consp thing)
1340            (eq (car thing) 'quote)
1341            (or (stringp (cadr thing))
1342                (symbolp (cadr thing))))))
1343
1344 (defun strip-quote (thing)
1345   (if (and (consp thing) (eq (car thing) 'quote))
1346       (cadr thing)
1347       thing))
1348 \f
1349 (defun compare-fields-form (val-form-1 val-form-2)
1350   (flet ((listify-fields (fields)
1351            (cond ((symbolp fields) fields)
1352                  ((every #'constantp fields) `',fields)
1353                  (t `(list ,@fields)))))
1354     (cond ((or (symbolp val-form-1) (symbolp val-form-2))
1355            `(equal ,(listify-fields val-form-1)
1356                    ,(listify-fields val-form-2)))
1357           (t
1358            `(and ,@(mapcar #'(lambda (v1 v2) `(= ,v1 ,v2))
1359                            val-form-1 val-form-2))))))
1360
1361 (defun compile-test (subj test funstate)
1362   (when (and (consp test) (symbolp (car test)) (not (keywordp (car test))))
1363     (setf subj (car test)
1364           test (cdr test)))
1365   (let ((key (if (consp test) (car test) test))
1366         (body (if (consp test) (cdr test) nil)))
1367     (cond ((null key)
1368            nil)
1369           ((eq key t)
1370            t)
1371           ((eq key :constant)
1372            (let* ((arg (arg-or-lose subj funstate))
1373                   (fields (arg-fields arg))
1374                   (consts body))
1375              (when (not (= (length fields) (length consts)))
1376                (pd-error "The number of constants doesn't match number of ~
1377                           fields in: (~S :constant~{ ~S~})"
1378                          subj body))
1379              (compare-fields-form (gen-arg-forms arg :numeric funstate)
1380                                   consts)))
1381           ((eq key :positive)
1382            `(> ,(arg-value-form (arg-or-lose subj funstate) funstate :numeric)
1383                0))
1384           ((eq key :negative)
1385            `(< ,(arg-value-form (arg-or-lose subj funstate) funstate :numeric)
1386                0))
1387           ((eq key :same-as)
1388            (let ((arg1 (arg-or-lose subj funstate))
1389                  (arg2 (arg-or-lose (car body) funstate)))
1390              (unless (and (= (length (arg-fields arg1))
1391                              (length (arg-fields arg2)))
1392                           (every #'(lambda (bs1 bs2)
1393                                      (= (byte-size bs1) (byte-size bs2)))
1394                                  (arg-fields arg1)
1395                                  (arg-fields arg2)))
1396                (pd-error "can't compare differently sized fields: ~
1397                           (~S :same-as ~S)" subj (car body)))
1398              (compare-fields-form (gen-arg-forms arg1 :numeric funstate)
1399                                   (gen-arg-forms arg2 :numeric funstate))))
1400           ((eq key :or)
1401            `(or ,@(mapcar #'(lambda (sub) (compile-test subj sub funstate))
1402                           body)))
1403           ((eq key :and)
1404            `(and ,@(mapcar #'(lambda (sub) (compile-test subj sub funstate))
1405                            body)))
1406           ((eq key :not)
1407            `(not ,(compile-test subj (car body) funstate)))
1408           ((and (consp key) (null body))
1409            (compile-test subj key funstate))
1410           (t
1411            (pd-error "bogus test-form: ~S" test)))))
1412 \f
1413 (defun find-labeller-fun (%name args cache)
1414   (let ((labelled-fields
1415          (mapcar #'arg-name (remove-if-not #'arg-use-label args))))
1416     (if (null labelled-fields)
1417         (values nil nil)
1418         (!with-cached-function
1419             (name funstate cache function-cache-labellers args
1420              :stem (concatenate 'string "LABELLER-" (string %name))
1421              :constraint labelled-fields)
1422           (let ((labels-form 'labels))
1423             (dolist (arg args)
1424               (when (arg-use-label arg)
1425                 (setf labels-form
1426                       `(let ((labels ,labels-form)
1427                              (addr
1428                               ,(arg-value-form arg funstate :adjusted nil)))
1429                          (if (assoc addr labels :test #'eq)
1430                              labels
1431                              (cons (cons addr nil) labels))))))
1432             `(defun ,name (chunk labels dstate)
1433                (declare (type list labels)
1434                         (type dchunk chunk)
1435                         (type disassem-state dstate)
1436                         ;; FIXME: This should be SPEED 0 but can't be
1437                         ;; until we support byte compilation of
1438                         ;; components of the SBCL system.
1439                         #+nil (optimize (speed 0) (safety 0) (debug 0)))
1440                (flet ((local-filtered-value (offset)
1441                         (declare (type filtered-value-index offset))
1442                         (aref (dstate-filtered-values dstate) offset))
1443                       (local-extract (bytespec)
1444                         (dchunk-extract chunk bytespec))
1445                       (adjust-label (val adjust-fun)
1446                         (funcall adjust-fun val dstate)))
1447                  (declare (ignorable #'local-filtered-value #'local-extract
1448                                      #'adjust-label)
1449                           (inline local-filtered-value local-extract
1450                                   adjust-label))
1451                  (let* ,(make-arg-temp-bindings funstate)
1452                    ,labels-form))))))))
1453
1454 (defun find-prefilter-fun (%name %format-name args cache)
1455   (declare (type (or symbol string) %name %format-name))
1456   (let ((filtered-args (mapcar #'arg-name
1457                                (remove-if-not #'arg-prefilter args))))
1458     (if (null filtered-args)
1459         (values nil nil)
1460         (!with-cached-function
1461             (name funstate cache function-cache-prefilters args
1462              :stem (concatenate 'string
1463                                 (string %name)
1464                                 "-"
1465                                 (string %format-name)
1466                                 "-PREFILTER")
1467              :constraint filtered-args)
1468           (collect ((forms))
1469             (dolist (arg args)
1470               (let ((pf (arg-prefilter arg)))
1471                 (when pf
1472                   (forms
1473                    `(setf (local-filtered-value ,(arg-position arg))
1474                           ,(maybe-listify
1475                             (gen-arg-forms arg :filtering funstate)))))
1476                 ))
1477             `(defun ,name (chunk dstate)
1478                (declare (type dchunk chunk)
1479                         (type disassem-state dstate)
1480                         ;; FIXME: This should be SPEED 0 but can't be
1481                         ;; until we support byte compilation of
1482                         ;; components of the SBCL system.
1483                         #+nil (optimize (speed 0) (safety 0) (debug 0)))
1484                (flet (((setf local-filtered-value) (value offset)
1485                        (declare (type filtered-value-index offset))
1486                        (setf (aref (dstate-filtered-values dstate) offset)
1487                              value))
1488                       (local-filter (value filter)
1489                                     (funcall filter value dstate))
1490                       (local-extract (bytespec)
1491                                      (dchunk-extract chunk bytespec)))
1492                 (declare (ignorable #'local-filter #'local-extract)
1493                          (inline (setf local-filtered-value)
1494                                  local-filter local-extract))
1495                 ;; Use them for side-effects only.
1496                 (let* ,(make-arg-temp-bindings funstate)
1497                   ,@(forms)))))))))
1498 \f
1499 (defun compute-mask-id (args)
1500   (let ((mask dchunk-zero)
1501         (id dchunk-zero))
1502     (dolist (arg args (values mask id))
1503       (let ((av (arg-value arg)))
1504         (when av
1505           (do ((fields (arg-fields arg) (cdr fields))
1506                (values (if (atom av) (list av) av) (cdr values)))
1507               ((null fields))
1508             (let ((field-mask (dchunk-make-mask (car fields))))
1509               (when (/= (dchunk-and mask field-mask) dchunk-zero)
1510                 (pd-error "The field ~S in arg ~S overlaps some other field."
1511                           (car fields)
1512                           (arg-name arg)))
1513               (dchunk-insertf id (car fields) (car values))
1514               (dchunk-orf mask field-mask))))))))
1515
1516 (defun install-inst-flavors (name flavors)
1517   (setf (gethash name *disassem-insts*)
1518         flavors))
1519 \f
1520 #!-sb-fluid (declaim (inline bytes-to-bits))
1521 (declaim (maybe-inline sign-extend aligned-p align tab tab0))
1522
1523 (defun bytes-to-bits (bytes)
1524   (declare (type length bytes))
1525   (* bytes sb!vm:byte-bits))
1526
1527 (defun bits-to-bytes (bits)
1528   (declare (type length bits))
1529   (multiple-value-bind (bytes rbits)
1530       (truncate bits sb!vm:byte-bits)
1531     (when (not (zerop rbits))
1532       (error "~D bits is not a byte-multiple." bits))
1533     bytes))
1534
1535 (defun sign-extend (int size)
1536   (declare (type integer int)
1537            (type (integer 0 128) size))
1538   (if (logbitp (1- size) int)
1539       (dpb int (byte size 0) -1)
1540       int))
1541
1542 (defun aligned-p (address size)
1543   #!+sb-doc
1544   "Returns non-NIL if ADDRESS is aligned on a SIZE byte boundary."
1545   (declare (type address address)
1546            (type alignment size))
1547   (zerop (logand (1- size) address)))
1548
1549 (defun align (address size)
1550   #!+sb-doc
1551   "Return ADDRESS aligned *upward* to a SIZE byte boundary."
1552   (declare (type address address)
1553            (type alignment size))
1554   (logandc1 (1- size) (+ (1- size) address)))
1555
1556 (defun tab (column stream)
1557   (funcall (formatter "~V,1t") stream column)
1558   nil)
1559 (defun tab0 (column stream)
1560   (funcall (formatter "~V,0t") stream column)
1561   nil)
1562
1563 (defun princ16 (value stream)
1564   (write value :stream stream :radix t :base 16 :escape nil))
1565 \f
1566 (defun read-signed-suffix (length dstate)
1567   (declare (type (member 8 16 32) length)
1568            (type disassem-state dstate)
1569            (optimize (speed 3) (safety 0)))
1570   (sign-extend (read-suffix length dstate) length))
1571
1572 ;;; KLUDGE: The associated run-time machinery for this is in
1573 ;;; target-disassem.lisp (much later). This is here just to make sure
1574 ;;; it's defined before it's used. -- WHN ca. 19990701
1575 (defmacro dstate-get-prop (dstate name)
1576   #!+sb-doc
1577   "Get the value of the property called NAME in DSTATE. Also setf'able."
1578   `(getf (dstate-properties ,dstate) ,name))