1.0.30.11: autogenerate tagname information for LDB in genesis
[sbcl.git] / src / compiler / debug.lisp
1 ;;;; This file contains utilities for debugging the compiler --
2 ;;;; currently only stuff for checking the consistency of the IR1.
3
4 ;;;; This software is part of the SBCL system. See the README file for
5 ;;;; more information.
6 ;;;;
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
12
13 (in-package "SB!C")
14
15 (defvar *args* ()
16   #!+sb-doc
17   "This variable is bound to the format arguments when an error is signalled
18   by BARF or BURP.")
19
20 (defvar *ignored-errors* (make-hash-table :test 'equal))
21
22 ;;; A definite inconsistency has been detected. Signal an error with
23 ;;; *args* bound to the list of the format args.
24 (declaim (ftype (function (string &rest t) (values)) barf))
25 (defun barf (string &rest *args*)
26   (unless (gethash string *ignored-errors*)
27     (restart-case
28         (apply #'error string *args*)
29       (continue ()
30         :report "Ignore this error.")
31       (ignore-all ()
32         :report "Ignore this and all future occurrences of this error."
33         (setf (gethash string *ignored-errors*) t))))
34   (values))
35
36 (defvar *burp-action* :warn
37   #!+sb-doc
38   "Action taken by the BURP function when a possible compiler bug is detected.
39   One of :WARN, :ERROR or :NONE.")
40 (declaim (type (member :warn :error :none) *burp-action*))
41
42 ;;; Called when something funny but possibly correct is noticed.
43 ;;; Otherwise similar to BARF.
44 (declaim (ftype (function (string &rest t) (values)) burp))
45 (defun burp (string &rest *args*)
46   (ecase *burp-action*
47     (:warn (apply #'warn string *args*))
48     (:error (apply #'cerror "press on anyway." string *args*))
49     (:none))
50   (values))
51
52 ;;; *SEEN-BLOCKS* is a hashtable with true values for all blocks which
53 ;;; appear in the DFO for one of the specified components.
54 ;;;
55 ;;; *SEEN-FUNS* is similar, but records all the lambdas we
56 ;;; reached by recursing on top level functions.
57 ;;; FIXME: Is it really only LAMBDAs, not e.g. FUNCTIONALs? Then
58 ;;; shouldn't it be *SEEN-LAMBDAS*?
59 (defvar *seen-blocks* (make-hash-table :test 'eq))
60 (defvar *seen-funs* (make-hash-table :test 'eq))
61
62 ;;; Barf if NODE is in a block which wasn't reached during the graph
63 ;;; walk.
64 (declaim (ftype (function (node) (values)) check-node-reached))
65 (defun check-node-reached (node)
66   (unless (gethash (ctran-block (node-prev node)) *seen-blocks*)
67     (barf "~S was not reached." node))
68   (values))
69
70 ;;; Check everything that we can think of for consistency. When a
71 ;;; definite inconsistency is detected, we BARF. Possible problems
72 ;;; just cause us to BURP. Our argument is a list of components, but
73 ;;; we also look at the *FREE-VARS*, *FREE-FUNS* and *CONSTANTS*.
74 ;;;
75 ;;; First we do a pre-pass which finds all the CBLOCKs and CLAMBDAs,
76 ;;; testing that they are linked together properly and entering them
77 ;;; in hashtables. Next, we iterate over the blocks again, looking at
78 ;;; the actual code and control flow. Finally, we scan the global leaf
79 ;;; hashtables, looking for lossage.
80 (declaim (ftype (function (list) (values)) check-ir1-consistency))
81 (defun check-ir1-consistency (components)
82   (clrhash *seen-blocks*)
83   (clrhash *seen-funs*)
84   (dolist (c components)
85     (let* ((head (component-head c))
86            (tail (component-tail c)))
87       (unless (and (null (block-pred head))
88                    (null (block-succ tail)))
89         (barf "~S is malformed." c))
90
91       (do ((prev nil block)
92            (block head (block-next block)))
93           ((null block)
94            (unless (eq prev tail)
95              (barf "wrong TAIL for DFO, ~S in ~S" prev c)))
96         (setf (gethash block *seen-blocks*) t)
97         (unless (eq (block-prev block) prev)
98           (barf "bad PREV for ~S, should be ~S" block prev))
99         (unless (or (eq block tail)
100                     (eq (block-component block) c))
101           (barf "~S is not in ~S." block c)))
102 #|
103       (when (or (loop-blocks c) (loop-inferiors c))
104         (do-blocks (block c :both)
105           (setf (block-flag block) nil))
106         (check-loop-consistency c nil)
107         (do-blocks (block c :both)
108           (unless (block-flag block)
109             (barf "~S was not in any loop." block))))
110 |#
111     ))
112
113   (check-fun-consistency components)
114
115   (dolist (c components)
116     (do ((block (block-next (component-head c)) (block-next block)))
117         ((null (block-next block)))
118       (check-block-consistency block)))
119
120   (maphash (lambda (k v)
121              (declare (ignore k))
122              (unless (or (constant-p v)
123                          (and (global-var-p v)
124                               (member (global-var-kind v)
125                                       '(:global :special :unknown))))
126                (barf "strange *FREE-VARS* entry: ~S" v))
127              (dolist (n (leaf-refs v))
128                (check-node-reached n))
129              (when (basic-var-p v)
130                (dolist (n (basic-var-sets v))
131                  (check-node-reached n))))
132            *free-vars*)
133
134   (maphash (lambda (k v)
135              (declare (ignore k))
136              (unless (constant-p v)
137                (barf "strange *CONSTANTS* entry: ~S" v))
138              (dolist (n (leaf-refs v))
139                (check-node-reached n)))
140            *constants*)
141
142   (maphash (lambda (k v)
143              (declare (ignore k))
144              (unless (or (functional-p v)
145                          (and (global-var-p v)
146                               (eq (global-var-kind v) :global-function)))
147                (barf "strange *FREE-FUNS* entry: ~S" v))
148              (dolist (n (leaf-refs v))
149                (check-node-reached n)))
150            *free-funs*)
151   (clrhash *seen-funs*)
152   (clrhash *seen-blocks*)
153   (values))
154 \f
155 ;;;; function consistency checking
156
157 (defun observe-functional (x)
158   (declare (type functional x))
159   (when (gethash x *seen-funs*)
160     (barf "~S was seen more than once." x))
161   (unless (eq (functional-kind x) :deleted)
162     (setf (gethash x *seen-funs*) t)))
163
164 ;;; Check that the specified function has been seen.
165 (defun check-fun-reached (fun where)
166   (declare (type functional fun))
167   (unless (gethash fun *seen-funs*)
168     (barf "unseen function ~S in ~S" fun where)))
169
170 ;;; In a CLAMBDA, check that the associated nodes are in seen blocks.
171 ;;; In an OPTIONAL-DISPATCH, check that the entry points were seen. If
172 ;;; the function is deleted, ignore it.
173 (defun check-fun-stuff (functional)
174   (ecase (functional-kind functional)
175     (:external
176      (let ((fun (functional-entry-fun functional)))
177        (check-fun-reached fun functional)
178        (when (functional-kind fun)
179          (barf "The function for XEP ~S has kind." functional))
180        (unless (eq (functional-entry-fun fun) functional)
181          (barf "bad back-pointer in function for XEP ~S" functional))))
182     ((:let :mv-let :assignment) ; i.e. SOMEWHAT-LETLIKE-P
183      (check-fun-reached (lambda-home functional) functional)
184      (when (functional-entry-fun functional)
185        (barf "The LET ~S has entry function." functional))
186      (unless (member functional (lambda-lets (lambda-home functional)))
187        (barf "The LET ~S is not in LETs for HOME." functional))
188      (unless (eq (functional-kind functional) :assignment)
189        (when (rest (leaf-refs functional))
190          (barf "The LET ~S has multiple references." functional)))
191      (when (lambda-lets functional)
192        (barf "LETs in a LET: ~S" functional)))
193     (:optional
194      (when (functional-entry-fun functional)
195        (barf ":OPTIONAL ~S has an ENTRY-FUN." functional))
196      (let ((ef (lambda-optional-dispatch functional)))
197        (check-fun-reached ef functional)
198        (unless (or (member functional (optional-dispatch-entry-points ef)
199                            :key (lambda (ep)
200                                   (when (promise-ready-p ep)
201                                     (force ep))))
202                    (eq functional (optional-dispatch-more-entry ef))
203                    (eq functional (optional-dispatch-main-entry ef)))
204          (barf ":OPTIONAL ~S is not an e-p for its OPTIONAL-DISPATCH ~S."
205                functional ef))))
206     (:toplevel
207      (unless (eq (functional-entry-fun functional) functional)
208        (barf "The ENTRY-FUN in ~S isn't a self-pointer." functional)))
209     ((nil :escape :cleanup)
210      (let ((ef (functional-entry-fun functional)))
211        (when ef
212          (check-fun-reached ef functional)
213          (unless (eq (functional-kind ef) :external)
214            (barf "The ENTRY-FUN in ~S isn't an XEP: ~S." functional ef)))))
215     (:deleted
216      (return-from check-fun-stuff)))
217
218   (case (functional-kind functional)
219     ((nil :optional :external :toplevel :escape :cleanup)
220      (when (lambda-p functional)
221        (dolist (fun (lambda-lets functional))
222          (unless (eq (lambda-home fun) functional)
223            (barf "The home in ~S is not ~S." fun functional))
224          (check-fun-reached fun functional))
225        (unless (eq (lambda-home functional) functional)
226          (barf "home not self-pointer in ~S" functional)))))
227
228   (etypecase functional
229     (clambda
230      (when (lambda-bind functional)
231        (check-node-reached (lambda-bind functional)))
232      (when (lambda-return functional)
233        (check-node-reached (lambda-return functional)))
234
235      (dolist (var (lambda-vars functional))
236        (dolist (ref (leaf-refs var))
237          (check-node-reached ref))
238        (dolist (set (basic-var-sets var))
239          (check-node-reached set))
240        (unless (eq (lambda-var-home var) functional)
241          (barf "HOME in ~S should be ~S." var functional))))
242     (optional-dispatch
243      (dolist (ep (optional-dispatch-entry-points functional))
244        (when (promise-ready-p ep)
245          (check-fun-reached (force ep) functional)))
246      (let ((more (optional-dispatch-more-entry functional)))
247        (when more (check-fun-reached more functional)))
248      (check-fun-reached (optional-dispatch-main-entry functional)
249                         functional))))
250
251 (defun check-fun-consistency (components)
252   (dolist (c components)
253     (dolist (new-fun (component-new-functionals c))
254       (observe-functional new-fun))
255     (dolist (fun (component-lambdas c))
256       (when (eq (functional-kind fun) :external)
257         (let ((ef (functional-entry-fun fun)))
258           (when (optional-dispatch-p ef)
259             (observe-functional ef))))
260       (observe-functional fun)
261       (dolist (let (lambda-lets fun))
262         (observe-functional let))))
263
264   (dolist (c components)
265     (dolist (new-fun (component-new-functionals c))
266       (check-fun-stuff new-fun))
267     (dolist (fun (component-lambdas c))
268       (when (eq (functional-kind fun) :deleted)
269         (barf "deleted lambda ~S in Lambdas for ~S" fun c))
270       (check-fun-stuff fun)
271       (dolist (let (lambda-lets fun))
272         (check-fun-stuff let)))))
273 \f
274 ;;;; loop consistency checking
275
276 #|
277 ;;; Descend through the loop nesting and check that the tree is well-formed
278 ;;; and that all blocks in the loops are known blocks. We also mark each block
279 ;;; that we see so that we can do a check later to detect blocks that weren't
280 ;;; in any loop.
281 (declaim (ftype (function (loop (or loop null)) (values)) check-loop-consistency))
282 (defun check-loop-consistency (loop superior)
283   (unless (eq (loop-superior loop) superior)
284     (barf "wrong superior in ~S, should be ~S" loop superior))
285   (when (and superior
286              (/= (loop-depth loop) (1+ (loop-depth superior))))
287     (barf "wrong depth in ~S" loop))
288
289   (dolist (tail (loop-tail loop))
290     (check-loop-block tail loop))
291   (dolist (exit (loop-exits loop))
292     (check-loop-block exit loop))
293   (check-loop-block (loop-head loop) loop)
294   (unless (eq (block-loop (loop-head loop)) loop)
295     (barf "The head of ~S is not directly in the loop." loop))
296
297   (do ((block (loop-blocks loop) (block-loop-next block)))
298       ((null block))
299     (setf (block-flag block) t)
300     (unless (gethash block *seen-blocks*)
301       (barf "unseen block ~S in Blocks for ~S" block loop))
302     (unless (eq (block-loop block) loop)
303       (barf "wrong loop in ~S, should be ~S" block loop)))
304
305   (dolist (inferior (loop-inferiors loop))
306     (check-loop-consistency inferior loop))
307   (values))
308
309 ;;; Check that Block is either in Loop or an inferior.
310 (declaim (ftype (function (block loop) (values)) check-loop-block))
311 (defun check-loop-block (block loop)
312   (unless (gethash block *seen-blocks*)
313     (barf "unseen block ~S in loop info for ~S" block loop))
314   (labels ((walk (l)
315              (if (eq (block-loop block) l)
316                  t
317                  (dolist (inferior (loop-inferiors l) nil)
318                    (when (walk inferior) (return t))))))
319     (unless (walk loop)
320       (barf "~S is in loop info for ~S but not in the loop." block loop)))
321   (values))
322
323 |#
324
325 ;;; Check a block for consistency at the general flow-graph level, and
326 ;;; call CHECK-NODE-CONSISTENCY on each node to locally check for
327 ;;; semantic consistency.
328 (declaim (ftype (function (cblock) (values)) check-block-consistency))
329 (defun check-block-consistency (block)
330
331   (dolist (pred (block-pred block))
332     (unless (gethash pred *seen-blocks*)
333       (barf "unseen predecessor ~S in ~S" pred block))
334     (unless (member block (block-succ pred))
335       (barf "bad predecessor link ~S in ~S" pred block)))
336
337   (let* ((fun (block-home-lambda block))
338          (fun-deleted (eq (functional-kind fun) :deleted))
339          (this-ctran (block-start block))
340          (last (block-last block)))
341     (unless fun-deleted
342       (check-fun-reached fun block))
343     (when (not this-ctran)
344       (barf "~S has no START." block))
345     (when (not last)
346       (barf "~S has no LAST." block))
347     (unless (eq (ctran-kind this-ctran) :block-start)
348       (barf "The START of ~S has the wrong kind." block))
349
350     (when (ctran-use this-ctran)
351       (barf "The ctran ~S is used." this-ctran))
352
353     (when (node-next last)
354       (barf "Last node ~S of ~S has next ctran." last block))
355
356     (loop
357       (unless (eq (ctran-block this-ctran) block)
358         (barf "BLOCK of ~S should be ~S." this-ctran block))
359
360       (let ((node (ctran-next this-ctran)))
361         (unless (node-p node)
362           (barf "~S has strange NEXT." this-ctran))
363         (unless (eq (node-prev node) this-ctran)
364           (barf "PREV in ~S should be ~S." node this-ctran))
365
366         (when (valued-node-p node)
367           (binding* ((lvar (node-lvar node) :exit-if-null))
368             (unless (memq node (find-uses lvar))
369               (barf "~S is not used by its LVAR ~S." node lvar))
370             (when (singleton-p (lvar-uses lvar))
371               (barf "~S has exactly 1 use, but LVAR-USES is a list."
372                     lvar))
373             (unless (lvar-dest lvar)
374               (barf "~S does not have dest." lvar))))
375
376         (check-node-reached node)
377         (unless fun-deleted
378           (check-node-consistency node))
379
380         (let ((next (node-next node)))
381           (when (and (not next) (not (eq node last)))
382             (barf "~S has no NEXT." node))
383           (when (eq node last) (return))
384           (unless (eq (ctran-kind next) :inside-block)
385             (barf "The interior ctran ~S in ~S has the wrong kind."
386                   next
387                   block))
388           (unless (ctran-next next)
389             (barf "~S has no NEXT." next))
390           (unless (eq (ctran-use next) node)
391             (barf "USE in ~S should be ~S." next node))
392           (setq this-ctran next))))
393
394     (check-block-successors block))
395   (values))
396
397 ;;; Check that BLOCK is properly terminated. Each successor must be
398 ;;; accounted for by the type of the last node.
399 (declaim (ftype (function (cblock) (values)) check-block-successors))
400 (defun check-block-successors (block)
401   (let ((last (block-last block))
402         (succ (block-succ block)))
403
404     (let* ((comp (block-component block)))
405       (dolist (b succ)
406         (unless (gethash b *seen-blocks*)
407           (barf "unseen successor ~S in ~S" b block))
408         (unless (member block (block-pred b))
409           (barf "bad successor link ~S in ~S" b block))
410         (unless (eq (block-component b) comp)
411           (barf "The successor ~S in ~S is in a different component."
412                 b
413                 block))))
414
415     (typecase last
416       (cif
417        (unless (proper-list-of-length-p succ 1 2)
418          (barf "~S ends in an IF, but doesn't have one or two successors."
419                block))
420        (unless (member (if-consequent last) succ)
421          (barf "The CONSEQUENT for ~S isn't in SUCC for ~S." last block))
422        (unless (member (if-alternative last) succ)
423          (barf "The ALTERNATIVE for ~S isn't in SUCC for ~S." last block)))
424       (creturn
425        (unless (if (eq (functional-kind (return-lambda last)) :deleted)
426                    (null succ)
427                    (and (= (length succ) 1)
428                         (eq (first succ)
429                             (component-tail (block-component block)))))
430          (barf "strange successors for RETURN in ~S" block)))
431       (exit
432        (unless (proper-list-of-length-p succ 0 1)
433          (barf "EXIT node with strange number of successors: ~S" last)))
434       (t
435        (unless (or (= (length succ) 1) (node-tail-p last)
436                    (and (block-delete-p block) (null succ)))
437          (barf "~S ends in normal node, but doesn't have one successor."
438                block)))))
439   (values))
440 \f
441 ;;;; node consistency checking
442
443 ;;; Check that the DEST for LVAR is the specified NODE. We also mark
444 ;;; the block LVAR is in as SEEN.
445 #+nil(declaim (ftype (function (lvar node) (values)) check-dest))
446 (defun check-dest (lvar node)
447   (do-uses (use lvar)
448     (unless (gethash (node-block use) *seen-blocks*)
449       (barf "Node ~S using ~S is in an unknown block." use lvar)))
450   (unless (eq (lvar-dest lvar) node)
451     (barf "DEST for ~S should be ~S." lvar node))
452   (unless (find-uses lvar)
453     (barf "Lvar ~S has a destinatin, but no uses."
454           lvar))
455   (values))
456
457 ;;; This function deals with checking for consistency of the
458 ;;; type-dependent information in a node.
459 (defun check-node-consistency (node)
460   (declare (type node node))
461   (etypecase node
462     (ref
463      (let ((leaf (ref-leaf node)))
464        (when (functional-p leaf)
465          (if (eq (functional-kind leaf) :toplevel-xep)
466              (unless (eq (component-kind (block-component (node-block node)))
467                          :toplevel)
468                (barf ":TOPLEVEL-XEP ref in non-top-level component: ~S"
469                      node))
470              (check-fun-reached leaf node)))))
471     (basic-combination
472      (check-dest (basic-combination-fun node) node)
473      (when (and (mv-combination-p node)
474                 (eq (basic-combination-kind node) :local))
475        (let ((fun-lvar (basic-combination-fun node)))
476          (unless (ref-p (lvar-uses fun-lvar))
477            (barf "function in a local mv-combination is not a LEAF: ~S" node))
478          (let ((fun (ref-leaf (lvar-use fun-lvar))))
479            (unless (lambda-p fun)
480              (barf "function ~S in a local mv-combination ~S is not local"
481                    fun node))
482            (unless (eq (functional-kind fun) :mv-let)
483              (barf "function ~S in a local mv-combination ~S is not of kind :MV-LET"
484                    fun node)))))
485      (dolist (arg (basic-combination-args node))
486        (cond
487          (arg (check-dest arg node))
488          ((not (and (eq (basic-combination-kind node) :local)
489                     (combination-p node)))
490           (barf "flushed arg not in local call: ~S" node))
491          (t
492           (locally
493               ;; KLUDGE: In sbcl-0.6.11.37, the compiler doesn't like
494               ;; (DECLARE (TYPE INDEX POS)) after the inline expansion of
495               ;; POSITION. It compiles it correctly, but it issues a type
496               ;; mismatch warning because it can't eliminate the
497               ;; possibility that control will flow through the
498               ;; NIL-returning branch. So we punt here. -- WHN 2001-04-15
499               (declare (notinline position))
500             (let ((fun (ref-leaf (lvar-use
501                                   (basic-combination-fun node))))
502                   (pos (position arg (basic-combination-args node))))
503               (declare (type index pos))
504               (when (leaf-refs (elt (lambda-vars fun) pos))
505                 (barf "flushed arg for referenced var in ~S" node)))))))
506      (let* ((lvar (node-lvar node))
507             (dest (and lvar (lvar-dest lvar))))
508        (when (and (return-p dest)
509                   (eq (basic-combination-kind node) :local)
510                   (not (eq (lambda-tail-set (combination-lambda node))
511                            (lambda-tail-set (return-lambda dest)))))
512          (barf "tail local call to function with different tail set:~%  ~S"
513                node))))
514     (cif
515      (check-dest (if-test node) node)
516      (unless (eq (block-last (node-block node)) node)
517        (barf "IF not at block end: ~S" node)))
518     (cset
519      (check-dest (set-value node) node))
520     (cast
521      (check-dest (cast-value node) node))
522     (bind
523      (check-fun-reached (bind-lambda node) node))
524     (creturn
525      (check-fun-reached (return-lambda node) node)
526      (check-dest (return-result node) node)
527      (unless (eq (block-last (node-block node)) node)
528        (barf "RETURN not at block end: ~S" node)))
529     (entry
530      (unless (member node (lambda-entries (node-home-lambda node)))
531        (barf "~S is not in ENTRIES for its home LAMBDA." node))
532      (dolist (exit (entry-exits node))
533        (unless (node-deleted exit)
534          (check-node-reached node))))
535     (exit
536      (let ((entry (exit-entry node))
537            (value (exit-value node)))
538        (cond (entry
539               (check-node-reached entry)
540               (unless (member node (entry-exits entry))
541                 (barf "~S is not in its ENTRY's EXITS." node))
542               (when value
543                 (check-dest value node)))
544              (t
545               (when value
546                 (barf "~S has VALUE but no ENTRY." node)))))))
547
548   (values))
549 \f
550 ;;;; IR2 consistency checking
551
552 ;;; Check for some kind of consistency in some REFs linked together by
553 ;;; TN-REF-ACROSS. VOP is the VOP that the references are in. WRITE-P
554 ;;; is the value of WRITE-P that should be present. COUNT is the
555 ;;; minimum number of operands expected. If MORE-P is true, then any
556 ;;; larger number will also be accepted. WHAT is a string describing
557 ;;; the kind of operand in error messages.
558 (defun check-tn-refs (refs vop write-p count more-p what)
559   (let ((vop-refs (vop-refs vop)))
560     (do ((ref refs (tn-ref-across ref))
561          (num 0 (1+ num)))
562         ((null ref)
563          (when (< num count)
564            (barf "There should be at least ~W ~A in ~S, but there are only ~W."
565                  count what vop num))
566          (when (and (not more-p) (> num count))
567            (barf "There should be ~W ~A in ~S, but are ~W."
568                  count what vop num)))
569       (unless (eq (tn-ref-vop ref) vop)
570         (barf "VOP is ~S isn't ~S." ref vop))
571       (unless (eq (tn-ref-write-p ref) write-p)
572         (barf "The WRITE-P in ~S isn't ~S." vop write-p))
573       (unless (find-in #'tn-ref-next-ref ref vop-refs)
574         (barf "~S not found in REFS for ~S" ref vop))
575       (unless (find-in #'tn-ref-next ref
576                        (if (tn-ref-write-p ref)
577                            (tn-writes (tn-ref-tn ref))
578                            (tn-reads (tn-ref-tn ref))))
579         (barf "~S not found in reads/writes for its TN" ref))
580
581       (let ((target (tn-ref-target ref)))
582         (when target
583           (unless (eq (tn-ref-write-p target) (not (tn-ref-write-p ref)))
584             (barf "The target for ~S isn't complementary WRITE-P." ref))
585           (unless (find-in #'tn-ref-next-ref target vop-refs)
586             (barf "The target for ~S isn't in REFS for ~S." ref vop)))))))
587
588 ;;; Verify the sanity of the VOP-REFS slot in VOP. This involves checking
589 ;;; that each referenced TN appears as an argument, result or temp, and also
590 ;;; basic checks for the plausibility of the specified ordering of the refs.
591 (defun check-vop-refs (vop)
592   (declare (type vop vop))
593   (do ((ref (vop-refs vop) (tn-ref-next-ref ref)))
594       ((null ref))
595     (cond
596      ((find-in #'tn-ref-across ref (vop-args vop)))
597      ((find-in #'tn-ref-across ref (vop-results vop)))
598      ((not (eq (tn-ref-vop ref) vop))
599       (barf "VOP in ~S isn't ~S." ref vop))
600      ((find-in #'tn-ref-across ref (vop-temps vop)))
601      ((tn-ref-write-p ref)
602       (barf "stray ref that isn't a READ: ~S" ref))
603      (t
604       (let* ((tn (tn-ref-tn ref))
605              (temp (find-in #'tn-ref-across tn (vop-temps vop)
606                             :key #'tn-ref-tn)))
607         (unless temp
608           (barf "stray ref with no corresponding temp write: ~S" ref))
609         (unless (find-in #'tn-ref-next-ref temp (tn-ref-next-ref ref))
610           (barf "Read is after write for temp ~S in refs of ~S."
611                 tn vop))))))
612   (values))
613
614 ;;; Check the basic sanity of the VOP linkage, then call some other
615 ;;; functions to check on the TN-REFS. We grab some info out of the
616 ;;; VOP-INFO to tell us what to expect.
617 ;;;
618 ;;; [### Check that operand type restrictions are met?]
619 (defun check-ir2-block-consistency (2block)
620   (declare (type ir2-block 2block))
621   (do ((vop (ir2-block-start-vop 2block)
622             (vop-next vop))
623        (prev nil vop))
624       ((null vop)
625        (unless (eq prev (ir2-block-last-vop 2block))
626          (barf "The last VOP in ~S should be ~S." 2block prev)))
627     (unless (eq (vop-prev vop) prev)
628       (barf "PREV in ~S should be ~S." vop prev))
629
630     (unless (eq (vop-block vop) 2block)
631       (barf "BLOCK in ~S should be ~S." vop 2block))
632
633     (check-vop-refs vop)
634
635     (let* ((info (vop-info vop))
636            (atypes (template-arg-types info))
637            (rtypes (template-result-types info)))
638       (check-tn-refs (vop-args vop) vop nil
639                      (count-if-not (lambda (x)
640                                      (and (consp x)
641                                           (eq (car x) :constant)))
642                                    atypes)
643                      (template-more-args-type info) "args")
644       (check-tn-refs (vop-results vop) vop t
645                      (if (template-conditional-p info) 0 (length rtypes))
646                      (template-more-results-type info) "results")
647       (check-tn-refs (vop-temps vop) vop t 0 t "temps")
648       (unless (= (length (vop-codegen-info vop))
649                  (template-info-arg-count info))
650         (barf "wrong number of codegen info args in ~S" vop))))
651   (values))
652
653 ;;; Check stuff about the IR2 representation of COMPONENT. This assumes the
654 ;;; sanity of the basic flow graph.
655 ;;;
656 ;;; [### Also grovel global TN data structures?  Assume pack not
657 ;;; done yet?  Have separate CHECK-TN-CONSISTENCY for pre-pack and
658 ;;; CHECK-PACK-CONSISTENCY for post-pack?]
659 (defun check-ir2-consistency (component)
660   (declare (type component component))
661   (do-ir2-blocks (block component)
662     (check-ir2-block-consistency block))
663   (values))
664 \f
665 ;;;; lifetime analysis checking
666
667 ;;; Dump some info about how many TNs there, and what the conflicts data
668 ;;; structures are like.
669 (defun pre-pack-tn-stats (component &optional (stream *standard-output*))
670   (declare (type component component))
671   (let ((wired 0)
672         (global 0)
673         (local 0)
674         (confs 0)
675         (unused 0)
676         (const 0)
677         (temps 0)
678         (environment 0)
679         (comp 0))
680     (do-packed-tns (tn component)
681       (let ((reads (tn-reads tn))
682             (writes (tn-writes tn)))
683         (when (and reads writes
684                    (not (tn-ref-next reads)) (not (tn-ref-next writes))
685                    (eq (tn-ref-vop reads) (tn-ref-vop writes)))
686           (incf temps)))
687       (when (tn-offset tn)
688         (incf wired))
689       (unless (or (tn-reads tn) (tn-writes tn))
690         (incf unused))
691       (cond ((eq (tn-kind tn) :component)
692              (incf comp))
693             ((tn-global-conflicts tn)
694              (case (tn-kind tn)
695                ((:environment :debug-environment) (incf environment))
696                (t (incf global)))
697              (do ((conf (tn-global-conflicts tn)
698                         (global-conflicts-next-tnwise conf)))
699                  ((null conf))
700                (incf confs)))
701             (t
702              (incf local))))
703
704     (do ((tn (ir2-component-constant-tns (component-info component))
705              (tn-next tn)))
706         ((null tn))
707       (incf const))
708
709     (format stream
710      "~%TNs: ~W local, ~W temps, ~W constant, ~W env, ~W comp, ~W global.~@
711        Wired: ~W, Unused: ~W. ~W block~:P, ~W global conflict~:P.~%"
712        local temps const environment comp global wired unused
713        (ir2-block-count component)
714        confs))
715   (values))
716
717 ;;; If the entry in Local-TNs for TN in BLOCK is :MORE, then do some checks
718 ;;; for the validity of the usage.
719 (defun check-more-tn-entry (tn block)
720   (let* ((vop (ir2-block-start-vop block))
721          (info (vop-info vop)))
722     (macrolet ((frob (more-p ops)
723                  `(and (,more-p info)
724                        (find-in #'tn-ref-across tn (,ops vop)
725                                 :key #'tn-ref-tn))))
726       (unless (and (eq vop (ir2-block-last-vop block))
727                    (or (frob template-more-args-type vop-args)
728                        (frob template-more-results-type vop-results)))
729         (barf "strange :MORE LTN entry for ~S in ~S" tn block))))
730   (values))
731
732 (defun check-tn-conflicts (component)
733   (do-packed-tns (tn component)
734     (unless (or (not (eq (tn-kind tn) :normal))
735                 (tn-reads tn)
736                 (tn-writes tn))
737       (barf "no references to ~S" tn))
738
739     (unless (tn-sc tn) (barf "~S has no SC." tn))
740
741     (let ((conf (tn-global-conflicts tn))
742           (kind (tn-kind tn)))
743       (cond
744        ((eq kind :component)
745         (unless (member tn (ir2-component-component-tns
746                             (component-info component)))
747           (barf "~S not in COMPONENT-TNs for ~S" tn component)))
748        (conf
749         (do ((conf conf (global-conflicts-next-tnwise conf))
750              (prev nil conf))
751             ((null conf))
752           (unless (eq (global-conflicts-tn conf) tn)
753             (barf "TN in ~S should be ~S." conf tn))
754
755           (unless (eq (global-conflicts-kind conf) :live)
756             (let* ((block (global-conflicts-block conf))
757                    (ltn (svref (ir2-block-local-tns block)
758                                (global-conflicts-number conf))))
759               (cond ((eq ltn tn))
760                     ((eq ltn :more) (check-more-tn-entry tn block))
761                     (t
762                      (barf "~S wrong in LTN map for ~S" conf tn)))))
763
764           (when prev
765             (unless (> (ir2-block-number (global-conflicts-block conf))
766                        (ir2-block-number (global-conflicts-block prev)))
767               (barf "~s and ~s out of order" prev conf)))))
768        ((member (tn-kind tn) '(:constant :specified-save)))
769        (t
770         (let ((local (tn-local tn)))
771           (unless local
772             (barf "~S has no global conflicts, but isn't local either." tn))
773           (unless (eq (svref (ir2-block-local-tns local)
774                              (tn-local-number tn))
775                       tn)
776             (barf "~S wrong in LTN map" tn))
777           (do ((ref (tn-reads tn) (tn-ref-next ref)))
778               ((null ref))
779             (unless (eq (vop-block (tn-ref-vop ref)) local)
780               (barf "~S has references in blocks other than its LOCAL block."
781                     tn)))
782           (do ((ref (tn-writes tn) (tn-ref-next ref)))
783               ((null ref))
784             (unless (eq (vop-block (tn-ref-vop ref)) local)
785               (barf "~S has references in blocks other than its LOCAL block."
786                     tn))))))))
787   (values))
788
789 (defun check-block-conflicts (component)
790   (do-ir2-blocks (block component)
791     (do ((conf (ir2-block-global-tns block)
792                (global-conflicts-next-blockwise conf))
793          (prev nil conf))
794         ((null conf))
795       (when prev
796         (unless (> (tn-number (global-conflicts-tn conf))
797                    (tn-number (global-conflicts-tn prev)))
798           (barf "~S and ~S out of order in ~S" prev conf block)))
799
800       (unless (find-in #'global-conflicts-next-tnwise
801                        conf
802                        (tn-global-conflicts
803                         (global-conflicts-tn conf)))
804         (barf "~S missing from global conflicts of its TN" conf)))
805
806     (let ((map (ir2-block-local-tns block)))
807       (dotimes (i (ir2-block-local-tn-count block))
808         (let ((tn (svref map i)))
809           (unless (or (eq tn :more)
810                       (null tn)
811                       (tn-global-conflicts tn)
812                       (eq (tn-local tn) block))
813             (barf "strange TN ~S in LTN map for ~S" tn block)))))))
814
815 ;;; All TNs live at the beginning of an environment must be passing
816 ;;; locations associated with that environment. We make an exception
817 ;;; for wired TNs in XEP functions, since we randomly reference wired
818 ;;; TNs to access the full call passing locations.
819 (defun check-environment-lifetimes (component)
820   (dolist (fun (component-lambdas component))
821     (let* ((env (lambda-physenv fun))
822            (2env (physenv-info env))
823            (vars (lambda-vars fun))
824            (closure (ir2-physenv-closure 2env))
825            (pc (ir2-physenv-return-pc-pass 2env))
826            (fp (ir2-physenv-old-fp 2env))
827            (2block (block-info (lambda-block (physenv-lambda env)))))
828       (do ((conf (ir2-block-global-tns 2block)
829                  (global-conflicts-next-blockwise conf)))
830           ((null conf))
831         (let ((tn (global-conflicts-tn conf)))
832           (unless (or (eq (global-conflicts-kind conf) :write)
833                       (eq tn pc)
834                       (eq tn fp)
835                       (and (xep-p fun) (tn-offset tn))
836                       (member (tn-kind tn) '(:environment :debug-environment))
837                       (member tn vars :key #'leaf-info)
838                       (member tn closure :key #'cdr))
839             (barf "strange TN live at head of ~S: ~S" env tn))))))
840   (values))
841
842 ;;; Check for some basic sanity in the TN conflict data structures,
843 ;;; and also check that no TNs are unexpectedly live at environment
844 ;;; entry.
845 (defun check-life-consistency (component)
846   (check-tn-conflicts component)
847   (check-block-conflicts component)
848   (check-environment-lifetimes component))
849 \f
850 ;;;; pack consistency checking
851
852 (defun check-pack-consistency (component)
853   (flet ((check (scs ops)
854            (do ((scs scs (cdr scs))
855                 (op ops (tn-ref-across op)))
856                ((null scs))
857              (let ((load-tn (tn-ref-load-tn op)))
858                (unless (eq (svref (car scs)
859                                   (sc-number
860                                    (tn-sc
861                                     (or load-tn (tn-ref-tn op)))))
862                            t)
863                  (barf "operand restriction not satisfied: ~S" op))))))
864     (do-ir2-blocks (block component)
865       (do ((vop (ir2-block-last-vop block) (vop-prev vop)))
866           ((null vop))
867         (let ((info (vop-info vop)))
868           (check (vop-info-result-load-scs info) (vop-results vop))
869           (check (vop-info-arg-load-scs info) (vop-args vop))))))
870   (values))
871 \f
872 ;;;; data structure dumping routines
873
874 ;;; When we print CONTINUATIONs and TNs, we assign them small numeric
875 ;;; IDs so that we can get a handle on anonymous objects given a
876 ;;; printout.
877 ;;;
878 ;;; FIXME:
879 ;;;   * Perhaps this machinery should be #!+SB-SHOW.
880 ;;;   * Probably the hash tables should either be weak hash tables,
881 ;;;     or only allocated within a single compilation unit. Otherwise
882 ;;;     there will be a tendency for them to grow without bound and
883 ;;;     keep garbage from being collected.
884 (macrolet ((def (counter vto vfrom fto ffrom)
885              `(progn
886                 (declaim (type hash-table ,vto ,vfrom))
887                 (defvar ,vto (make-hash-table :test 'eq))
888                 (defvar ,vfrom (make-hash-table :test 'eql))
889                 (declaim (type fixnum ,counter))
890                 (defvar ,counter 0)
891
892                 (defun ,fto (x)
893                   (or (gethash x ,vto)
894                       (let ((num (incf ,counter)))
895                         (setf (gethash num ,vfrom) x)
896                         (setf (gethash x ,vto) num))))
897
898                 (defun ,ffrom (num)
899                   (values (gethash num ,vfrom))))))
900   (def *continuation-number* *continuation-numbers* *number-continuations*
901        cont-num num-cont)
902   (def *tn-id* *tn-ids* *id-tns* tn-id id-tn)
903   (def *label-id* *id-labels* *label-ids* label-id id-label))
904
905 ;;; Print a terse one-line description of LEAF.
906 (defun print-leaf (leaf &optional (stream *standard-output*))
907   (declare (type leaf leaf) (type stream stream))
908   (etypecase leaf
909     (lambda-var (prin1 (leaf-debug-name leaf) stream))
910     (constant (format stream "'~S" (constant-value leaf)))
911     (global-var
912      (format stream "~S {~A}" (leaf-debug-name leaf) (global-var-kind leaf)))
913     (functional
914      (format stream "~S ~S" (type-of leaf) (functional-debug-name leaf)))))
915
916 ;;; Attempt to find a block given some thing that has to do with it.
917 (declaim (ftype (sfunction (t) cblock) block-or-lose))
918 (defun block-or-lose (thing)
919   (ctypecase thing
920     (cblock thing)
921     (ir2-block (ir2-block-block thing))
922     (vop (block-or-lose (vop-block thing)))
923     (tn-ref (block-or-lose (tn-ref-vop thing)))
924     (ctran (ctran-block thing))
925     (node (node-block thing))
926     (component (component-head thing))
927 #|    (cloop (loop-head thing))|#
928     (integer (ctran-block (num-cont thing)))
929     (functional (lambda-block (main-entry thing)))
930     (null (error "Bad thing: ~S." thing))
931     (symbol (block-or-lose (gethash thing *free-funs*)))))
932
933 ;;; Print cN.
934 (defun print-continuation (cont)
935   (declare (type continuation cont))
936   (format t " c~D" (cont-num cont))
937   (values))
938
939 (defun print-ctran (cont)
940   (declare (type ctran cont))
941   (format t "c~D " (cont-num cont))
942   (values))
943 (defun print-lvar (cont)
944   (declare (type lvar cont))
945   (format t "v~D " (cont-num cont))
946   (values))
947
948 (defun print-lvar-stack (stack &optional (stream *standard-output*))
949   (loop for (lvar . rest) on stack
950         do (format stream "~:[u~;d~]v~D~@[ ~]"
951                    (lvar-dynamic-extent lvar) (cont-num lvar) rest)))
952
953 ;;; Print out the nodes in BLOCK in a format oriented toward
954 ;;; representing what the code does.
955 (defun print-nodes (block)
956   (setq block (block-or-lose block))
957   (pprint-logical-block (nil nil)
958     (format t "~:@_IR1 block ~D start c~D"
959             (block-number block) (cont-num (block-start block)))
960     (when (block-delete-p block)
961       (format t " <deleted>"))
962
963     (pprint-newline :mandatory)
964     (awhen (block-info block)
965       (format t "start stack: ")
966       (print-lvar-stack (ir2-block-start-stack it))
967       (pprint-newline :mandatory))
968     (do ((ctran (block-start block) (node-next (ctran-next ctran))))
969         ((not ctran))
970       (let ((node (ctran-next ctran)))
971         (format t "~3D>~:[    ~;~:*~3D:~] "
972                 (cont-num ctran)
973                 (when (and (valued-node-p node) (node-lvar node))
974                   (cont-num (node-lvar node))))
975         (etypecase node
976           (ref (print-leaf (ref-leaf node)))
977           (basic-combination
978            (let ((kind (basic-combination-kind node)))
979              (format t "~(~A~A ~A~) "
980                      (if (node-tail-p node) "tail " "")
981                      kind
982                      (type-of node))
983              (print-lvar (basic-combination-fun node))
984              (dolist (arg (basic-combination-args node))
985                (if arg
986                    (print-lvar arg)
987                    (format t "<none> ")))))
988           (cset
989            (write-string "set ")
990            (print-leaf (set-var node))
991            (write-char #\space)
992            (print-lvar (set-value node)))
993           (cif
994            (write-string "if ")
995            (print-lvar (if-test node))
996            (print-ctran (block-start (if-consequent node)))
997            (print-ctran (block-start (if-alternative node))))
998           (bind
999            (write-string "bind ")
1000            (print-leaf (bind-lambda node))
1001            (when (functional-kind (bind-lambda node))
1002              (format t " ~S ~S" :kind (functional-kind (bind-lambda node)))))
1003           (creturn
1004            (write-string "return ")
1005            (print-lvar (return-result node))
1006            (print-leaf (return-lambda node)))
1007           (entry
1008            (let ((cleanup (entry-cleanup node)))
1009              (case (cleanup-kind cleanup)
1010                ((:dynamic-extent)
1011                 (format t "entry DX~{ v~D~}"
1012                         (mapcar (lambda (lvar-or-cell)
1013                                   (if (consp lvar-or-cell)
1014                                       (cons (car lvar-or-cell)
1015                                             (cont-num (cdr lvar-or-cell)))
1016                                       (cont-num lvar-or-cell)))
1017                                 (cleanup-info cleanup))))
1018                (t
1019                 (format t "entry ~S" (entry-exits node))))))
1020           (exit
1021            (let ((value (exit-value node)))
1022              (cond (value
1023                     (format t "exit ")
1024                     (print-lvar value))
1025                    ((exit-entry node)
1026                     (format t "exit <no value>"))
1027                    (t
1028                     (format t "exit <degenerate>")))))
1029           (cast
1030            (let ((value (cast-value node)))
1031              (format t "cast v~D ~A[~S -> ~S]" (cont-num value)
1032                      (if (cast-%type-check node) #\+ #\-)
1033                      (cast-type-to-check node)
1034                      (cast-asserted-type node)))))
1035         (pprint-newline :mandatory)))
1036
1037     (awhen (block-info block)
1038       (format t "end stack: ")
1039       (print-lvar-stack (ir2-block-end-stack it))
1040       (pprint-newline :mandatory))
1041     (let ((succ (block-succ block)))
1042       (format t "successors~{ c~D~}~%"
1043               (mapcar (lambda (x) (cont-num (block-start x))) succ))))
1044   (values))
1045
1046 ;;; Print the guts of a TN. (logic shared between PRINT-OBJECT (TN T)
1047 ;;; and printers for compound objects which contain TNs)
1048 (defun print-tn-guts (tn &optional (stream *standard-output*))
1049   (declare (type tn tn))
1050   (let ((leaf (tn-leaf tn)))
1051     (cond (leaf
1052            (print-leaf leaf stream)
1053            (format stream "!~D" (tn-id tn)))
1054           (t
1055            (format stream "t~D" (tn-id tn))))
1056     (when (and (tn-sc tn) (tn-offset tn))
1057       (format stream "[~A]" (location-print-name tn)))))
1058
1059 ;;; Print the TN-REFs representing some operands to a VOP, linked by
1060 ;;; TN-REF-ACROSS.
1061 (defun print-operands (refs)
1062   (declare (type (or tn-ref null) refs))
1063   (pprint-logical-block (*standard-output* nil)
1064     (do ((ref refs (tn-ref-across ref)))
1065         ((null ref))
1066       (let ((tn (tn-ref-tn ref))
1067             (ltn (tn-ref-load-tn ref)))
1068         (cond ((not ltn)
1069                (print-tn-guts tn))
1070               (t
1071                (print-tn-guts tn)
1072                (princ (if (tn-ref-write-p ref) #\< #\>))
1073                (print-tn-guts ltn)))
1074         (princ #\space)
1075         (pprint-newline :fill)))))
1076
1077 ;;; Print the VOP, putting args, info and results on separate lines, if
1078 ;;; necessary.
1079 (defun print-vop (vop)
1080   (pprint-logical-block (*standard-output* nil)
1081     (princ (vop-info-name (vop-info vop)))
1082     (princ #\space)
1083     (pprint-indent :current 0)
1084     (print-operands (vop-args vop))
1085     (pprint-newline :linear)
1086     (when (vop-codegen-info vop)
1087       (princ (with-output-to-string (stream)
1088                (let ((*print-level* 1)
1089                      (*print-length* 3))
1090                  (format stream "{~{~S~^ ~}} " (vop-codegen-info vop)))))
1091       (pprint-newline :linear))
1092     (when (vop-results vop)
1093       (princ "=> ")
1094       (print-operands (vop-results vop))))
1095   (pprint-newline :mandatory))
1096
1097 ;;; Print the VOPs in the specified IR2 block.
1098 (defun print-ir2-block (block)
1099   (declare (type ir2-block block))
1100   (pprint-logical-block (*standard-output* nil)
1101     (cond
1102       ((eq (block-info (ir2-block-block block)) block)
1103        (format t "~:@_IR2 block ~D start c~D~:@_"
1104                (ir2-block-number block)
1105                (cont-num (block-start (ir2-block-block block))))
1106        (let ((label (ir2-block-%label block)))
1107          (when label
1108            (format t "L~D:~:@_" (label-id label)))))
1109       (t
1110        (format t "<overflow>~:@_")))
1111
1112     (do ((vop (ir2-block-start-vop block)
1113               (vop-next vop))
1114          (number 0 (1+ number)))
1115         ((null vop))
1116       (format t "~W: " number)
1117       (print-vop vop))))
1118
1119 ;;; This is like PRINT-NODES, but dumps the IR2 representation of the
1120 ;;; code in BLOCK.
1121 (defun print-vops (block)
1122   (setq block (block-or-lose block))
1123   (let ((2block (block-info block)))
1124     (print-ir2-block 2block)
1125     (do ((b (ir2-block-next 2block) (ir2-block-next b)))
1126         ((not (eq (ir2-block-block b) block)))
1127       (print-ir2-block b)))
1128   (values))
1129
1130 ;;; Scan the IR2 blocks in emission order.
1131 (defun print-ir2-blocks (thing &optional full)
1132   (let* ((block (component-head (block-component (block-or-lose thing))))
1133          (2block (block-info block)))
1134     (pprint-logical-block (nil nil)
1135       (loop while 2block
1136          do (setq block (ir2-block-block 2block))
1137          do (pprint-logical-block (*standard-output* nil)
1138               (if full
1139                   (print-nodes block)
1140                   (format t "IR1 block ~D start c~D"
1141                           (block-number block)
1142                           (cont-num (block-start block))))
1143               (pprint-indent :block 4)
1144               (pprint-newline :mandatory)
1145               (loop while (and 2block (eq (ir2-block-block 2block) block))
1146                  do (print-ir2-block 2block)
1147                  do (setq 2block (ir2-block-next 2block))))
1148          do (pprint-newline :mandatory))))
1149   (values))
1150
1151 ;;; Do a PRINT-NODES on BLOCK and all blocks reachable from it by
1152 ;;; successor links.
1153 (defun print-blocks (block)
1154   (setq block (block-or-lose block))
1155   (do-blocks (block (block-component block) :both)
1156     (setf (block-flag block) nil))
1157   (labels ((walk (block)
1158              (unless (block-flag block)
1159                (setf (block-flag block) t)
1160                (when (block-start block)
1161                  (print-nodes block))
1162                (dolist (block (block-succ block))
1163                  (walk block)))))
1164     (walk block))
1165   (values))
1166
1167 ;;; Print all blocks in BLOCK's component in DFO.
1168 (defun print-all-blocks (thing)
1169   (do-blocks (block (block-component (block-or-lose thing)))
1170     (handler-case (print-nodes block)
1171       (error (condition)
1172         (format t "~&~A...~%" condition))))
1173   (values))
1174
1175 (defvar *list-conflicts-table* (make-hash-table :test 'eq))
1176
1177 ;;; Add all ALWAYS-LIVE TNs in BLOCK to the conflicts. TN is ignored
1178 ;;; when it appears in the global conflicts.
1179 (defun add-always-live-tns (block tn)
1180   (declare (type ir2-block block) (type tn tn))
1181   (do ((conf (ir2-block-global-tns block)
1182              (global-conflicts-next-blockwise conf)))
1183       ((null conf))
1184     (when (eq (global-conflicts-kind conf) :live)
1185       (let ((btn (global-conflicts-tn conf)))
1186         (unless (eq btn tn)
1187           (setf (gethash btn *list-conflicts-table*) t)))))
1188   (values))
1189
1190 ;;; Add all local TNs in BLOCK to the conflicts.
1191 (defun add-all-local-tns (block)
1192   (declare (type ir2-block block))
1193   (let ((ltns (ir2-block-local-tns block)))
1194     (dotimes (i (ir2-block-local-tn-count block))
1195       (setf (gethash (svref ltns i) *list-conflicts-table*) t)))
1196   (values))
1197
1198 ;;; Make a list out of all of the recorded conflicts.
1199 (defun listify-conflicts-table ()
1200   (collect ((res))
1201     (maphash (lambda (k v)
1202                (declare (ignore v))
1203                (when k
1204                  (res k)))
1205              *list-conflicts-table*)
1206     (clrhash *list-conflicts-table*)
1207     (res)))
1208
1209 ;;; Return a list of a the TNs that conflict with TN. Sort of, kind
1210 ;;; of. For debugging use only. Probably doesn't work on :COMPONENT TNs.
1211 (defun list-conflicts (tn)
1212   (aver (member (tn-kind tn) '(:normal :environment :debug-environment)))
1213   (let ((confs (tn-global-conflicts tn)))
1214     (cond (confs
1215            (clrhash *list-conflicts-table*)
1216            (do ((conf confs (global-conflicts-next-tnwise conf)))
1217                ((null conf))
1218              (format t "~&#<block ~D kind ~S>~%"
1219                      (block-number (ir2-block-block (global-conflicts-block
1220                                                      conf)))
1221                      (global-conflicts-kind conf))
1222              (let ((block (global-conflicts-block conf)))
1223                (add-always-live-tns block tn)
1224                (if (eq (global-conflicts-kind conf) :live)
1225                    (add-all-local-tns block)
1226                    (let ((bconf (global-conflicts-conflicts conf))
1227                          (ltns (ir2-block-local-tns block)))
1228                      (dotimes (i (ir2-block-local-tn-count block))
1229                        (when (/= (sbit bconf i) 0)
1230                          (setf (gethash (svref ltns i) *list-conflicts-table*)
1231                                t)))))))
1232            (listify-conflicts-table))
1233           (t
1234            (let* ((block (tn-local tn))
1235                   (ltns (ir2-block-local-tns block))
1236                   (confs (tn-local-conflicts tn)))
1237              (collect ((res))
1238                (dotimes (i (ir2-block-local-tn-count block))
1239                  (when (/= (sbit confs i) 0)
1240                    (let ((tn (svref ltns i)))
1241                      (when (and tn (not (eq tn :more))
1242                                 (not (tn-global-conflicts tn)))
1243                        (res tn)))))
1244                (do ((gtn (ir2-block-global-tns block)
1245                          (global-conflicts-next-blockwise gtn)))
1246                    ((null gtn))
1247                  (when (or (eq (global-conflicts-kind gtn) :live)
1248                            (/= (sbit confs (global-conflicts-number gtn)) 0))
1249                    (res (global-conflicts-tn gtn))))
1250                (res)))))))
1251
1252 (defun nth-vop (thing n)
1253   #!+sb-doc
1254   "Return the Nth VOP in the IR2-BLOCK pointed to by THING."
1255   (let ((block (block-info (block-or-lose thing))))
1256     (do ((i 0 (1+ i))
1257          (vop (ir2-block-start-vop block) (vop-next vop)))
1258         ((= i n) vop))))