more conservative classoid-name clearing
[sbcl.git] / src / compiler / tn.lisp
1 ;;;; This file contains utilities used for creating and manipulating
2 ;;;; TNs, and some other more assorted IR2 utilities.
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 ;;; The component that is currently being compiled. TNs are allocated
16 ;;; in this component.
17 (defvar *component-being-compiled*)
18
19 ;;; DO-PACKED-TNS (TN-Var Component [Result]) Declaration* Form*
20 ;;;
21 ;;; Iterate over all packed TNs allocated in COMPONENT.
22 (defmacro do-packed-tns ((tn component &optional result) &body body)
23   (let ((n-component (gensym)))
24     `(let ((,n-component (component-info ,component)))
25        (do ((,tn (ir2-component-normal-tns ,n-component) (tn-next ,tn)))
26            ((null ,tn))
27          ,@body)
28        (do ((,tn (ir2-component-restricted-tns ,n-component) (tn-next ,tn)))
29            ((null ,tn))
30          ,@body)
31        (do ((,tn (ir2-component-wired-tns ,n-component) (tn-next ,tn)))
32            ((null ,tn)
33             ,result)
34          ,@body))))
35 \f
36 (defun set-ir2-physenv-live-tns (value instance)
37   (setf (ir2-physenv-live-tns instance) value))
38
39 (defun set-ir2-physenv-debug-live-tns (value instance)
40   (setf (ir2-physenv-debug-live-tns instance) value))
41
42 (defun set-ir2-component-alias-tns (value instance)
43   (setf (ir2-component-alias-tns instance) value))
44
45 (defun set-ir2-component-normal-tns (value instance)
46   (setf (ir2-component-normal-tns instance) value))
47
48 (defun set-ir2-component-restricted-tns (value instance)
49   (setf (ir2-component-restricted-tns instance) value))
50
51 (defun set-ir2-component-wired-tns (value instance)
52   (setf (ir2-component-wired-tns instance) value))
53
54 ;;; Remove all TNs with no references from the lists of unpacked TNs.
55 ;;; We null out the OFFSET so that nobody will mistake deleted wired
56 ;;; TNs for properly packed TNs. We mark non-deleted alias TNs so that
57 ;;; aliased TNs aren't considered to be unreferenced.
58 (defun delete-unreferenced-tns (component)
59   (let* ((2comp (component-info component))
60          (aliases (make-array (1+ (ir2-component-global-tn-counter 2comp))
61                               :element-type 'bit :initial-element 0)))
62     (labels ((delete-some (getter setter)
63                (let ((prev nil))
64                  (do ((tn (funcall getter 2comp) (tn-next tn)))
65                      ((null tn))
66                    (cond
67                     ((or (used-p tn)
68                          (and (eq (tn-kind tn) :specified-save)
69                               (used-p (tn-save-tn tn))))
70                      (setq prev tn))
71                     (t
72                      (delete-1 tn prev setter))))))
73              (used-p (tn)
74                (or (tn-reads tn) (tn-writes tn)
75                    (member (tn-kind tn) '(:component :environment))
76                    (not (zerop (sbit aliases (tn-number tn))))))
77              (delete-1 (tn prev setter)
78                (if prev
79                    (setf (tn-next prev) (tn-next tn))
80                    (funcall setter (tn-next tn) 2comp))
81                (setf (tn-offset tn) nil)
82                (case (tn-kind tn)
83                  (:environment
84                   (clear-live tn
85                               #'ir2-physenv-live-tns
86                               #'set-ir2-physenv-live-tns))
87                  (:debug-environment
88                   (clear-live tn
89                               #'ir2-physenv-debug-live-tns
90                               #'set-ir2-physenv-debug-live-tns))))
91              (clear-live (tn getter setter)
92                (let ((env (physenv-info (tn-physenv tn))))
93                  (funcall setter (delete tn (funcall getter env)) env))))
94       (declare (inline used-p delete-some delete-1 clear-live))
95       (delete-some #'ir2-component-alias-tns
96                    #'set-ir2-component-alias-tns)
97       (do ((tn (ir2-component-alias-tns 2comp) (tn-next tn)))
98           ((null tn))
99         (setf (sbit aliases (tn-number (tn-save-tn tn))) 1))
100       (delete-some #'ir2-component-normal-tns
101                    #'set-ir2-component-normal-tns)
102       (delete-some #'ir2-component-restricted-tns
103                    #'set-ir2-component-restricted-tns)
104       (delete-some #'ir2-component-wired-tns
105                    #'set-ir2-component-wired-tns)))
106   (values))
107 \f
108 ;;;; TN creation
109
110 ;;; Create a packed TN of the specified primitive-type in the
111 ;;; *COMPONENT-BEING-COMPILED*. We use the SCs from the primitive type
112 ;;; to determine which SCs it can be packed in.
113 (defun make-normal-tn (type)
114   (declare (type primitive-type type))
115   (let* ((component (component-info *component-being-compiled*))
116          (res (make-tn (incf (ir2-component-global-tn-counter component))
117                        :normal type nil)))
118     (push-in tn-next res (ir2-component-normal-tns component))
119     res))
120
121 ;;; Create a normal packed TN with representation indicated by SCN.
122 (defun make-representation-tn (ptype scn)
123   (declare (type primitive-type ptype) (type sc-number scn))
124   (let* ((component (component-info *component-being-compiled*))
125          (res (make-tn (incf (ir2-component-global-tn-counter component))
126                        :normal ptype
127                        (svref *backend-sc-numbers* scn))))
128     (push-in tn-next res (ir2-component-normal-tns component))
129     res))
130
131 ;;; Create a TN wired to a particular location in an SC. We set the Offset
132 ;;; and FSC to record where it goes, and then put it on the current component's
133 ;;; Wired-TNs list. Ptype is the TN's primitive-type, which may be NIL in VOP
134 ;;; temporaries.
135 (defun make-wired-tn (ptype scn offset)
136   (declare (type (or primitive-type null) ptype)
137            (type sc-number scn) (type unsigned-byte offset))
138   (let* ((component (component-info *component-being-compiled*))
139          (res (make-tn (incf (ir2-component-global-tn-counter component))
140                        :normal ptype
141                        (svref *backend-sc-numbers* scn))))
142     (setf (tn-offset res) offset)
143     (push-in tn-next res (ir2-component-wired-tns component))
144     res))
145
146 ;;; Create a packed TN restricted to the SC with number SCN. Ptype is as
147 ;;; for MAKE-WIRED-TN.
148 (defun make-restricted-tn (ptype scn)
149   (declare (type (or primitive-type null) ptype) (type sc-number scn))
150   (let* ((component (component-info *component-being-compiled*))
151          (res (make-tn (incf (ir2-component-global-tn-counter component))
152                        :normal ptype
153                        (svref *backend-sc-numbers* scn))))
154     (push-in tn-next res (ir2-component-restricted-tns component))
155     res))
156
157 ;;; Make TN be live throughout PHYSENV. Return TN. In the DEBUG case,
158 ;;; the TN is treated normally in blocks in the environment which
159 ;;; reference the TN, allowing targeting to/from the TN. This results
160 ;;; in move efficient code, but may result in the TN sometimes not
161 ;;; being live when you want it.
162 (defun physenv-live-tn (tn physenv)
163   (declare (type tn tn) (type physenv physenv))
164   (aver (eq (tn-kind tn) :normal))
165   (setf (tn-kind tn) :environment)
166   (setf (tn-physenv tn) physenv)
167   (push tn (ir2-physenv-live-tns (physenv-info physenv)))
168   tn)
169 (defun physenv-debug-live-tn (tn physenv)
170   (declare (type tn tn) (type physenv physenv))
171   (aver (eq (tn-kind tn) :normal))
172   (setf (tn-kind tn) :debug-environment)
173   (setf (tn-physenv tn) physenv)
174   (push tn (ir2-physenv-debug-live-tns (physenv-info physenv)))
175   tn)
176
177 ;;; Make TN be live throughout the current component. Return TN.
178 (defun component-live-tn (tn)
179   (declare (type tn tn))
180   (aver (eq (tn-kind tn) :normal))
181   (setf (tn-kind tn) :component)
182   (push tn (ir2-component-component-tns (component-info
183                                          *component-being-compiled*)))
184   tn)
185
186 ;;; Specify that SAVE be used as the save location for TN. TN is returned.
187 (defun specify-save-tn (tn save)
188   (declare (type tn tn save))
189   (aver (eq (tn-kind save) :normal))
190   (aver (and (not (tn-save-tn tn)) (not (tn-save-tn save))))
191   (setf (tn-kind save) :specified-save)
192   (setf (tn-save-tn tn) save)
193   (setf (tn-save-tn save) tn)
194   (push save
195         (ir2-component-specified-save-tns
196          (component-info *component-being-compiled*)))
197   tn)
198
199 ;;; Create a constant TN. The implementation dependent
200 ;;; IMMEDIATE-CONSTANT-SC function is used to determine whether the
201 ;;; constant has an immediate representation.
202 (defun make-constant-tn (constant boxedp)
203   (declare (type constant constant))
204   (let* ((immed (immediate-constant-sc (constant-value constant)))
205          (use-immed-p (and immed
206                            (or (not boxedp)
207                                (boxed-immediate-sc-p immed)))))
208     (cond
209       ;; CONSTANT-TN uses two caches, one for boxed and one for unboxed uses.
210       ;;
211       ;; However, in the case of USE-IMMED-P we can have the same TN for both
212       ;; uses. The first two legs here take care of that by cross-pollinating the
213       ;; cached values.
214       ;;
215       ;; Similarly, when there is no immediate SC.
216       ((and (or use-immed-p (not immed)) boxedp (leaf-info constant)))
217       ((and (or use-immed-p (not immed)) (not boxedp) (constant-boxed-tn constant)))
218       (t
219        (let* ((component (component-info *component-being-compiled*))
220               (sc (svref *backend-sc-numbers*
221                          (if use-immed-p
222                              immed
223                              (sc-number-or-lose 'constant))))
224               (res (make-tn 0 :constant (primitive-type (leaf-type constant)) sc)))
225          (unless use-immed-p
226            (let ((constants (ir2-component-constants component)))
227              (setf (tn-offset res) (fill-pointer constants))
228              (vector-push-extend constant constants)))
229          (push-in tn-next res (ir2-component-constant-tns component))
230          (setf (tn-leaf res) constant)
231          res)))))
232
233 (defun make-load-time-value-tn (handle type)
234   (let* ((component (component-info *component-being-compiled*))
235          (sc (svref *backend-sc-numbers*
236                     (sc-number-or-lose 'constant)))
237          (res (make-tn 0 :constant (primitive-type type) sc))
238          (constants (ir2-component-constants component)))
239     (setf (tn-offset res) (fill-pointer constants))
240     (vector-push-extend (cons :load-time-value handle) constants)
241     (push-in tn-next res (ir2-component-constant-tns component))
242     res))
243
244 ;;; Make a TN that aliases TN for use in local call argument passing.
245 (defun make-alias-tn (tn)
246   (declare (type tn tn))
247   (let* ((component (component-info *component-being-compiled*))
248          (res (make-tn (incf (ir2-component-global-tn-counter component))
249                        :alias (tn-primitive-type tn) nil)))
250     (setf (tn-save-tn res) tn)
251     (push-in tn-next res
252              (ir2-component-alias-tns component))
253     res))
254
255 ;;; Return a load-time constant TN with the specified KIND and INFO.
256 ;;; If the desired CONSTANTS entry already exists, then reuse it,
257 ;;; otherwise allocate a new load-time constant slot.
258 (defun make-load-time-constant-tn (kind info)
259   (declare (type keyword kind))
260   (let* ((component (component-info *component-being-compiled*))
261          (res (make-tn 0
262                        :constant
263                        *backend-t-primitive-type*
264                        (svref *backend-sc-numbers*
265                               (sc-number-or-lose 'constant))))
266          (constants (ir2-component-constants component)))
267
268     (do ((i 0 (1+ i)))
269         ((= i (length constants))
270          (setf (tn-offset res) i)
271          (vector-push-extend (cons kind info) constants))
272       (let ((entry (aref constants i)))
273         (when (and (consp entry)
274                    (eq (car entry) kind)
275                    (or (eq (cdr entry) info)
276                        (and (consp info)
277                             (equal (cdr entry) info))))
278           (setf (tn-offset res) i)
279           (return))))
280
281     (push-in tn-next res (ir2-component-constant-tns component))
282     res))
283 \f
284 ;;;; TN referencing
285
286 ;;; Make a TN-REF that references TN and return it. WRITE-P should be
287 ;;; true if this is a write reference, otherwise false. All we do
288 ;;; other than calling the constructor is add the reference to the
289 ;;; TN's references.
290 (defun reference-tn (tn write-p)
291   (declare (type tn tn) (type boolean write-p))
292   (let ((res (make-tn-ref tn write-p)))
293     (if write-p
294         (push-in tn-ref-next res (tn-writes tn))
295         (push-in tn-ref-next res (tn-reads tn)))
296     res))
297
298 ;;; Make TN-REFS to reference each TN in TNs, linked together by
299 ;;; TN-REF-ACROSS. WRITE-P is the WRITE-P value for the refs. MORE is
300 ;;; stuck in the TN-REF-ACROSS of the ref for the last TN, or returned
301 ;;; as the result if there are no TNs.
302 (defun reference-tn-list (tns write-p &optional more)
303   (declare (list tns) (type boolean write-p) (type (or tn-ref null) more))
304   (if tns
305       (let* ((first (reference-tn (first tns) write-p))
306              (prev first))
307         (dolist (tn (rest tns))
308           (let ((res (reference-tn tn write-p)))
309             (setf (tn-ref-across prev) res)
310             (setq prev res)))
311         (setf (tn-ref-across prev) more)
312         first)
313       more))
314
315 ;;; Remove Ref from the references for its associated TN.
316 (defun delete-tn-ref (ref)
317   (declare (type tn-ref ref))
318   (if (tn-ref-write-p ref)
319       (deletef-in tn-ref-next (tn-writes (tn-ref-tn ref)) ref)
320       (deletef-in tn-ref-next (tn-reads (tn-ref-tn ref)) ref))
321   (values))
322
323 ;;; Do stuff to change the TN referenced by Ref. We remove Ref from its
324 ;;; old TN's refs, add ref to TN's refs, and set the TN-REF-TN.
325 (defun change-tn-ref-tn (ref tn)
326   (declare (type tn-ref ref) (type tn tn))
327   (delete-tn-ref ref)
328   (setf (tn-ref-tn ref) tn)
329   (if (tn-ref-write-p ref)
330       (push-in tn-ref-next ref (tn-writes tn))
331       (push-in tn-ref-next ref (tn-reads tn)))
332   (values))
333 \f
334 ;;;; miscellaneous utilities
335
336 ;;; Emit a move-like template determined at run-time, with X as the
337 ;;; argument and Y as the result. Useful for move, coerce and
338 ;;; type-check templates. If supplied, then insert before VOP,
339 ;;; otherwise insert at then end of the block. Returns the last VOP
340 ;;; inserted.
341 (defun emit-move-template (node block template x y &optional before)
342   (declare (type node node) (type ir2-block block)
343            (type template template) (type tn x y))
344   (let ((arg (reference-tn x nil))
345         (result (reference-tn y t)))
346     (multiple-value-bind (first last)
347         (funcall (template-emit-function template) node block template arg
348                  result)
349       (insert-vop-sequence first last block before)
350       last)))
351
352 ;;; like EMIT-MOVE-TEMPLATE, except that we pass in INFO args too
353 (defun emit-load-template (node block template x y info &optional before)
354   (declare (type node node) (type ir2-block block)
355            (type template template) (type tn x y))
356   (let ((arg (reference-tn x nil))
357         (result (reference-tn y t)))
358     (multiple-value-bind (first last)
359         (funcall (template-emit-function template) node block template arg
360                  result info)
361       (insert-vop-sequence first last block before)
362       last)))
363
364 ;;; like EMIT-MOVE-TEMPLATE, except that the VOP takes two args
365 (defun emit-move-arg-template (node block template x f y &optional before)
366   (declare (type node node) (type ir2-block block)
367            (type template template) (type tn x f y))
368   (let ((x-ref (reference-tn x nil))
369         (f-ref (reference-tn f nil))
370         (y-ref (reference-tn y t)))
371     (setf (tn-ref-across x-ref) f-ref)
372     (multiple-value-bind (first last)
373         (funcall (template-emit-function template) node block template x-ref
374                  y-ref)
375       (insert-vop-sequence first last block before)
376       last)))
377
378 ;;; like EMIT-MOVE-TEMPLATE, except that the VOP takes no args
379 (defun emit-context-template (node block template y &optional before)
380   (declare (type node node) (type ir2-block block)
381            (type template template) (type tn y))
382   (let ((y-ref (reference-tn y t)))
383     (multiple-value-bind (first last)
384         (funcall (template-emit-function template) node block template nil
385                  y-ref)
386       (insert-vop-sequence first last block before)
387       last)))
388
389 ;;; Return the label marking the start of Block, assigning one if necessary.
390 (defun block-label (block)
391   (declare (type cblock block))
392   (let ((2block (block-info block)))
393     (or (ir2-block-%label 2block)
394         (setf (ir2-block-%label 2block) (gen-label)))))
395 (defun block-trampoline (block)
396   (declare (type cblock block))
397   (let ((2block (block-info block)))
398     (or (ir2-block-%trampoline-label 2block)
399         (setf (ir2-block-%trampoline-label 2block) (gen-label)))))
400
401 ;;; Return true if Block is emitted immediately after the block ended by Node.
402 (defun drop-thru-p (node block)
403   (declare (type node node) (type cblock block))
404   (let ((next-block (ir2-block-next (block-info (node-block node)))))
405     (aver (eq node (block-last (node-block node))))
406     (eq next-block (block-info block))))
407 (defun register-drop-thru (block)
408   (declare (type cblock block))
409   (let ((2block (block-info block)))
410     (setf (ir2-block-dropped-thru-to 2block) t))
411   nil)
412
413 ;;; Link a list of VOPs from First to Last into Block, Before the specified
414 ;;; VOP. If Before is NIL, insert at the end.
415 (defun insert-vop-sequence (first last block before)
416   (declare (type vop first last) (type ir2-block block)
417            (type (or vop null) before))
418   (if before
419       (let ((prev (vop-prev before)))
420         (setf (vop-prev first) prev)
421         (if prev
422             (setf (vop-next prev) first)
423             (setf (ir2-block-start-vop block) first))
424         (setf (vop-next last) before)
425         (setf (vop-prev before) last))
426       (let ((current (ir2-block-last-vop block)))
427         (setf (vop-prev first) current)
428         (setf (ir2-block-last-vop block) last)
429         (if current
430             (setf (vop-next current) first)
431             (setf (ir2-block-start-vop block) first))))
432   (values))
433
434 ;;; Delete all of the TN-REFs associated with VOP and remove VOP from the IR2.
435 (defun delete-vop (vop)
436   (declare (type vop vop))
437   (do ((ref (vop-refs vop) (tn-ref-next-ref ref)))
438       ((null ref))
439     (delete-tn-ref ref))
440
441   (let ((prev (vop-prev vop))
442         (next (vop-next vop))
443         (block (vop-block vop)))
444     (if prev
445         (setf (vop-next prev) next)
446         (setf (ir2-block-start-vop block) next))
447     (if next
448         (setf (vop-prev next) prev)
449         (setf (ir2-block-last-vop block) prev)))
450
451   (values))
452
453 ;;; Return a list of N normal TNs of the specified primitive type.
454 (defun make-n-tns (n ptype)
455   (declare (type unsigned-byte n) (type primitive-type ptype))
456   (loop repeat n
457         collect (make-normal-tn ptype)))
458
459 ;;; Return true if X and Y are packed in the same location, false otherwise.
460 ;;; This is false if either operand is constant.
461 (defun location= (x y)
462   (declare (type tn x y))
463   (and (eq (sc-sb (tn-sc x)) (sc-sb (tn-sc y)))
464        (eql (tn-offset x) (tn-offset y))
465        (not (or (eq (tn-kind x) :constant)
466                 (eq (tn-kind y) :constant)))))
467
468 ;;; Return the value of an immediate constant TN.
469 (defun tn-value (tn)
470   (declare (type tn tn))
471   (aver (eq (tn-kind tn) :constant))
472   (constant-value (tn-leaf tn)))
473
474 (defun immediate-tn-p (tn)
475   (declare (type tn tn))
476   (let ((leaf (tn-leaf tn)))
477     ;; Leaves with KIND :CONSTANT can have NIL as the leaf if they
478     ;; represent load time values.
479     (and leaf
480          (eq (tn-kind tn) :constant)
481          (eq (immediate-constant-sc (constant-value leaf))
482              (sc-number-or-lose 'sb!vm::immediate)))))
483
484 ;;; Force TN to be allocated in a SC that doesn't need to be saved: an
485 ;;; unbounded non-save-p SC. We don't actually make it a real "restricted" TN,
486 ;;; but since we change the SC to an unbounded one, we should always succeed in
487 ;;; packing it in that SC.
488 (defun force-tn-to-stack (tn)
489   (declare (type tn tn))
490   (let ((sc (tn-sc tn)))
491     (unless (and (not (sc-save-p sc))
492                  (eq (sb-kind (sc-sb sc)) :unbounded))
493       (dolist (alt (sc-alternate-scs sc)
494                    (error "SC ~S has no :UNBOUNDED :SAVE-P NIL alternate SC."
495                           (sc-name sc)))
496         (when (and (not (sc-save-p alt))
497                    (eq (sb-kind (sc-sb alt)) :unbounded))
498           (setf (tn-sc tn) alt)
499           (return)))))
500   (values))
501