1 ;;;; This file contains utilities used for creating and manipulating
2 ;;;; TNs, and some other more assorted IR2 utilities.
4 ;;;; This software is part of the SBCL system. See the README file for
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.
15 ;;; The component that is currently being compiled. TNs are allocated
16 ;;; in this component.
17 (defvar *component-being-compiled
*)
19 ;;; DO-PACKED-TNS (TN-Var Component [Result]) Form*
21 ;;; Iterate over all packed TNs allocated in COMPONENT.
22 (defmacro do-packed-tns
((tn component
&optional result
) &body body
)
23 (with-unique-names (n-component tns more-tns outer inner
)
24 `(prog* ((,n-component
(component-info ,component
))
25 (,tn
(ir2-component-normal-tns ,n-component
))
26 (,tns
(ir2-component-restricted-tns ,n-component
))
27 (,more-tns
(ir2-component-wired-tns ,n-component
)))
28 (when ,tn
(go ,inner
))
29 ,outer
(when (eq ,tns
:done
) (return ,result
))
30 (shiftf ,tn
,tns
,more-tns
:done
)
31 (unless ,tn
(go ,outer
))
33 (if (setq ,tn
(tn-next ,tn
)) (go ,inner
) (go ,outer
)))))
35 (defun set-ir2-physenv-live-tns (value instance
)
36 (setf (ir2-physenv-live-tns instance
) value
))
38 (defun set-ir2-physenv-debug-live-tns (value instance
)
39 (setf (ir2-physenv-debug-live-tns instance
) value
))
41 (defun set-ir2-component-alias-tns (value instance
)
42 (setf (ir2-component-alias-tns instance
) value
))
44 (defun set-ir2-component-normal-tns (value instance
)
45 (setf (ir2-component-normal-tns instance
) value
))
47 (defun set-ir2-component-restricted-tns (value instance
)
48 (setf (ir2-component-restricted-tns instance
) value
))
50 (defun set-ir2-component-wired-tns (value instance
)
51 (setf (ir2-component-wired-tns instance
) value
))
53 ;;; Remove all TNs with no references from the lists of unpacked TNs.
54 ;;; We null out the OFFSET so that nobody will mistake deleted wired
55 ;;; TNs for properly packed TNs. We mark non-deleted alias TNs so that
56 ;;; aliased TNs aren't considered to be unreferenced.
57 (defun delete-unreferenced-tns (component)
58 (let* ((2comp (component-info component
))
59 (aliases (make-array (1+ (ir2-component-global-tn-counter 2comp
))
60 :element-type
'bit
:initial-element
0)))
61 (labels ((delete-some (getter setter
)
63 (do ((tn (funcall getter
2comp
) (tn-next tn
)))
67 (and (eq (tn-kind tn
) :specified-save
)
68 (used-p (tn-save-tn tn
))))
71 (delete-1 tn prev setter
))))))
73 (or (tn-reads tn
) (tn-writes tn
)
74 (member (tn-kind tn
) '(:component
:environment
))
75 (not (zerop (sbit aliases
(tn-number tn
))))))
76 (delete-1 (tn prev setter
)
78 (setf (tn-next prev
) (tn-next tn
))
79 (funcall setter
(tn-next tn
) 2comp
))
80 (setf (tn-offset tn
) nil
)
84 #'ir2-physenv-live-tns
85 #'set-ir2-physenv-live-tns
))
88 #'ir2-physenv-debug-live-tns
89 #'set-ir2-physenv-debug-live-tns
))))
90 (clear-live (tn getter setter
)
91 (let ((env (physenv-info (tn-physenv tn
))))
92 (funcall setter
(delete tn
(funcall getter env
)) env
))))
93 (declare (inline used-p delete-some delete-1 clear-live
))
94 (delete-some #'ir2-component-alias-tns
95 #'set-ir2-component-alias-tns
)
96 (do ((tn (ir2-component-alias-tns 2comp
) (tn-next tn
)))
98 (setf (sbit aliases
(tn-number (tn-save-tn tn
))) 1))
99 (delete-some #'ir2-component-normal-tns
100 #'set-ir2-component-normal-tns
)
101 (delete-some #'ir2-component-restricted-tns
102 #'set-ir2-component-restricted-tns
)
103 (delete-some #'ir2-component-wired-tns
104 #'set-ir2-component-wired-tns
)))
109 ;;; Create a packed TN of the specified primitive-type in the
110 ;;; *COMPONENT-BEING-COMPILED*. We use the SCs from the primitive type
111 ;;; to determine which SCs it can be packed in.
112 (defun make-normal-tn (type)
113 (declare (type primitive-type type
))
114 (let* ((component (component-info *component-being-compiled
*))
115 (res (make-tn (incf (ir2-component-global-tn-counter component
))
117 (push-in tn-next res
(ir2-component-normal-tns component
))
120 ;;; Create a normal packed TN with representation indicated by SCN.
121 (defun make-representation-tn (ptype scn
)
122 (declare (type primitive-type ptype
) (type sc-number scn
))
123 (let* ((component (component-info *component-being-compiled
*))
124 (res (make-tn (incf (ir2-component-global-tn-counter component
))
126 (svref *backend-sc-numbers
* scn
))))
127 (push-in tn-next res
(ir2-component-normal-tns component
))
130 ;;; Create a TN wired to a particular location in an SC. We set the Offset
131 ;;; and FSC to record where it goes, and then put it on the current component's
132 ;;; Wired-TNs list. Ptype is the TN's primitive-type, which may be NIL in VOP
134 (defun make-wired-tn (ptype scn offset
)
135 (declare (type (or primitive-type null
) ptype
)
136 (type sc-number scn
) (type unsigned-byte offset
))
137 (let* ((component (component-info *component-being-compiled
*))
138 (res (make-tn (incf (ir2-component-global-tn-counter component
))
140 (svref *backend-sc-numbers
* scn
))))
141 (setf (tn-offset res
) offset
)
142 (push-in tn-next res
(ir2-component-wired-tns component
))
144 (defun sb!vm
::make-wired-tn
* (prim-type-name scn offset
)
145 (make-wired-tn (primitive-type-or-lose prim-type-name
) scn offset
))
147 ;;; Create a packed TN restricted to the SC with number SCN. Ptype is as
148 ;;; for MAKE-WIRED-TN.
149 (defun make-restricted-tn (ptype scn
)
150 (declare (type (or primitive-type null
) ptype
) (type sc-number scn
))
151 (let* ((component (component-info *component-being-compiled
*))
152 (res (make-tn (incf (ir2-component-global-tn-counter component
))
154 (svref *backend-sc-numbers
* scn
))))
155 (push-in tn-next res
(ir2-component-restricted-tns component
))
158 (defun make-unused-tn ()
159 (make-tn (incf (ir2-component-global-tn-counter (component-info *component-being-compiled
*)))
162 ;;; Make TN be live throughout PHYSENV. Return TN. In the DEBUG case,
163 ;;; the TN is treated normally in blocks in the environment which
164 ;;; reference the TN, allowing targeting to/from the TN. This results
165 ;;; in move efficient code, but may result in the TN sometimes not
166 ;;; being live when you want it.
167 (defun physenv-live-tn (tn physenv
)
168 (declare (type tn tn
) (type physenv physenv
))
169 (aver (eq (tn-kind tn
) :normal
))
170 (setf (tn-kind tn
) :environment
)
171 (setf (tn-physenv tn
) physenv
)
172 (push tn
(ir2-physenv-live-tns (physenv-info physenv
)))
174 (defun physenv-debug-live-tn (tn physenv
)
175 (declare (type tn tn
) (type physenv physenv
))
176 (aver (eq (tn-kind tn
) :normal
))
177 (setf (tn-kind tn
) :debug-environment
)
178 (setf (tn-physenv tn
) physenv
)
179 (push tn
(ir2-physenv-debug-live-tns (physenv-info physenv
)))
182 ;;; Make TN be live throughout the current component. Return TN.
183 (defun component-live-tn (tn)
184 (declare (type tn tn
))
185 (aver (eq (tn-kind tn
) :normal
))
186 (setf (tn-kind tn
) :component
)
187 (push tn
(ir2-component-component-tns (component-info
188 *component-being-compiled
*)))
191 ;;; Specify that SAVE be used as the save location for TN. TN is returned.
192 #!-fp-and-pc-standard-save
193 (defun specify-save-tn (tn save
)
194 (declare (type tn tn save
))
195 (aver (eq (tn-kind save
) :normal
))
196 (aver (and (not (tn-save-tn tn
)) (not (tn-save-tn save
))))
197 (setf (tn-kind save
) :specified-save
)
198 (setf (tn-save-tn tn
) save
)
199 (setf (tn-save-tn save
) tn
)
201 (ir2-component-specified-save-tns
202 (component-info *component-being-compiled
*)))
205 ;;; Create a constant TN. The backend dependent
206 ;;; IMMEDIATE-CONSTANT-SC function is used to determine whether the
207 ;;; constant has an immediate representation.
208 (defun make-constant-tn (constant)
209 (declare (type constant constant
))
210 (or (leaf-info constant
)
211 (let* ((immed (immediate-constant-sc (constant-value constant
)))
212 (boxed (or (not immed
)
213 (boxed-immediate-sc-p immed
))))
214 (let* ((component (component-info *component-being-compiled
*))
215 ;; If a constant have either an immediate or boxed
216 ;; representation (e.g. double-float) postpone the SC
217 ;; choice until SELECT-REPRESENTATIONS.
220 (svref *backend-sc-numbers
* immed
)
221 (sc-or-lose 'constant
))))
222 (res (make-tn 0 :constant
(primitive-type (leaf-type constant
)) sc
)))
223 ;; Objects of type SYMBOL can be immediate but they still go in the constants
224 ;; because liveness depends on pointer tracing without looking at code-fixups.
228 (let ((val (constant-value constant
)))
229 (or (and (symbolp val
) (not (sb!vm
:static-symbol-p val
)))
230 (typep val
'layout
)))))
231 (let ((constants (ir2-component-constants component
)))
232 (setf (tn-offset res
)
233 (vector-push-extend constant constants
))
234 (setf (leaf-info constant
) res
)))
235 (push-in tn-next res
(ir2-component-constant-tns component
))
236 (setf (tn-leaf res
) constant
)
239 (defun make-load-time-value-tn (handle type
)
240 (let* ((component (component-info *component-being-compiled
*))
241 (sc (svref *backend-sc-numbers
*
242 (sc-number-or-lose 'constant
)))
243 (res (make-tn 0 :constant
(primitive-type type
) sc
))
244 (constants (ir2-component-constants component
)))
245 (setf (tn-offset res
) (fill-pointer constants
))
246 (vector-push-extend (cons :load-time-value handle
) constants
)
247 (push-in tn-next res
(ir2-component-constant-tns component
))
250 ;;; Make a TN that aliases TN for use in local call argument passing.
251 (defun make-alias-tn (tn)
252 (declare (type tn tn
))
253 (let* ((component (component-info *component-being-compiled
*))
254 (res (make-tn (incf (ir2-component-global-tn-counter component
))
255 :alias
(tn-primitive-type tn
) nil
)))
256 (setf (tn-save-tn res
) tn
)
258 (ir2-component-alias-tns component
))
261 ;;; Return a load-time constant TN with the specified KIND and INFO.
262 ;;; If the desired CONSTANTS entry already exists, then reuse it,
263 ;;; otherwise allocate a new load-time constant slot.
264 (defun make-load-time-constant-tn (kind info
)
265 (declare (type keyword kind
))
266 (let* ((component (component-info *component-being-compiled
*))
269 *backend-t-primitive-type
*
270 (svref *backend-sc-numbers
*
271 (sc-number-or-lose 'constant
))))
272 (constants (ir2-component-constants component
)))
275 ((= i
(length constants
))
276 (setf (tn-offset res
) i
)
277 (vector-push-extend (cons kind info
) constants
))
278 (let ((entry (aref constants i
)))
279 (when (and (consp entry
)
280 (eq (car entry
) kind
)
281 (or (eq (cdr entry
) info
)
283 (equal (cdr entry
) info
))))
284 (setf (tn-offset res
) i
)
287 (push-in tn-next res
(ir2-component-constant-tns component
))
292 ;;; Make a TN-REF that references TN and return it. WRITE-P should be
293 ;;; true if this is a write reference, otherwise false. All we do
294 ;;; other than calling the constructor is add the reference to the
296 (defun reference-tn (tn write-p
)
297 (declare (type tn tn
) (type boolean write-p
))
298 (let ((res (make-tn-ref tn write-p
)))
299 (unless (eql (tn-kind tn
) :unused
)
301 (push-in tn-ref-next res
(tn-writes tn
))
302 (push-in tn-ref-next res
(tn-reads tn
))))
305 ;;; Make TN-REFS to reference each TN in TNs, linked together by
306 ;;; TN-REF-ACROSS. WRITE-P is the WRITE-P value for the refs. MORE is
307 ;;; stuck in the TN-REF-ACROSS of the ref for the last TN, or returned
308 ;;; as the result if there are no TNs.
309 (defun reference-tn-list (tns write-p
&optional more
)
310 (declare (list tns
) (type boolean write-p
) (type (or tn-ref null
) more
))
312 (let* ((first (reference-tn (first tns
) write-p
))
314 (dolist (tn (rest tns
))
315 (let ((res (reference-tn tn write-p
)))
316 (setf (tn-ref-across prev
) res
)
318 (setf (tn-ref-across prev
) more
)
322 ;;; Remove Ref from the references for its associated TN.
323 (defun delete-tn-ref (ref)
324 (declare (type tn-ref ref
))
325 (if (tn-ref-write-p ref
)
326 (deletef-in tn-ref-next
(tn-writes (tn-ref-tn ref
)) ref
)
327 (deletef-in tn-ref-next
(tn-reads (tn-ref-tn ref
)) ref
))
330 ;;; Do stuff to change the TN referenced by Ref. We remove Ref from its
331 ;;; old TN's refs, add ref to TN's refs, and set the TN-REF-TN.
332 (defun change-tn-ref-tn (ref tn
)
333 (declare (type tn-ref ref
) (type tn tn
))
335 (setf (tn-ref-tn ref
) tn
)
336 (if (tn-ref-write-p ref
)
337 (push-in tn-ref-next ref
(tn-writes tn
))
338 (push-in tn-ref-next ref
(tn-reads tn
)))
341 ;;;; miscellaneous utilities
343 ;;; Emit a move-like template determined at run-time, with X as the
344 ;;; argument and Y as the result. Useful for move, coerce and
345 ;;; type-check templates. If supplied, then insert before VOP,
346 ;;; otherwise insert at then end of the block. Returns the last VOP
348 (defun emit-move-template (node block template x y
&optional before
)
349 (declare (type node node
) (type ir2-block block
)
350 (type template template
) (type tn x y
))
351 (let ((arg (reference-tn x nil
))
352 (result (reference-tn y t
)))
353 (emit-and-insert-vop node block template arg result before
)))
355 ;;; like EMIT-MOVE-TEMPLATE, except that we pass in INFO args too
356 (defun emit-load-template (node block template x y info
&optional before
)
357 (declare (type node node
) (type ir2-block block
)
358 (type template template
) (type tn x y
))
359 (let ((arg (reference-tn x nil
))
360 (result (reference-tn y t
)))
361 (emit-and-insert-vop node block template arg result before info
)))
363 ;;; like EMIT-MOVE-TEMPLATE, except that the VOP takes two args
364 (defun emit-move-arg-template (node block template x f y
&optional before
)
365 (declare (type node node
) (type ir2-block block
)
366 (type template template
) (type tn x f y
))
367 (let ((x-ref (reference-tn x nil
))
368 (f-ref (reference-tn f nil
))
369 (y-ref (reference-tn y t
)))
370 (setf (tn-ref-across x-ref
) f-ref
)
371 (emit-and-insert-vop node block template x-ref y-ref before
)))
373 ;;; like EMIT-MOVE-TEMPLATE, except that the VOP takes no args
374 (defun emit-context-template (node block template y
&optional before
)
375 (declare (type node node
) (type ir2-block block
)
376 (type template template
) (type tn y
))
377 (let ((y-ref (reference-tn y t
)))
378 (emit-and-insert-vop node block template nil y-ref before
)))
380 ;;; Return the label marking the start of Block, assigning one if necessary.
381 (defun block-label (block)
382 (declare (type cblock block
))
383 (let ((2block (block-info block
)))
384 (or (ir2-block-%label
2block
)
385 (setf (ir2-block-%label
2block
) (gen-label)))))
386 (defun block-trampoline (block)
387 (declare (type cblock block
))
388 (let ((2block (block-info block
)))
389 (or (ir2-block-%trampoline-label
2block
)
390 (setf (ir2-block-%trampoline-label
2block
) (gen-label)))))
392 ;;; Return true if Block is emitted immediately after the block ended by Node.
393 (defun drop-thru-p (node block
)
394 (declare (type node node
) (type cblock block
))
395 (let ((next-block (ir2-block-next (block-info (node-block node
)))))
396 (aver (eq node
(block-last (node-block node
))))
397 (eq next-block
(block-info block
))))
398 (defun register-drop-thru (block)
399 (declare (type cblock block
))
400 (let ((2block (block-info block
)))
401 (setf (ir2-block-dropped-thru-to 2block
) t
))
404 ;;; Insert a VOP into BLOCK, before the specified
405 ;;; BEFORE VOP. If BEFORE is NIL, insert at the end.
406 (defun insert-vop (vop block before
)
407 (declare (type vop vop
) (type ir2-block block
)
408 (type (or vop null
) before
))
410 (let ((prev (vop-prev before
)))
411 (setf (vop-prev vop
) prev
)
413 (setf (vop-next prev
) vop
)
414 (setf (ir2-block-start-vop block
) vop
))
415 (setf (vop-next vop
) before
)
416 (setf (vop-prev before
) vop
))
417 (let ((current (ir2-block-last-vop block
)))
418 (setf (vop-prev vop
) current
)
419 (setf (ir2-block-last-vop block
) vop
)
421 (setf (vop-next current
) vop
)
422 (setf (ir2-block-start-vop block
) vop
))))
425 (defun emit-and-insert-vop (node block template arg result before
427 (let ((vop (emit-vop node block template arg result info
)))
428 (insert-vop vop block before
)
431 ;;; Delete all of the TN-REFs associated with VOP and remove VOP from the IR2.
432 (defun delete-vop (vop)
433 (declare (type vop vop
))
434 (do ((ref (vop-refs vop
) (tn-ref-next-ref ref
)))
438 (let ((prev (vop-prev vop
))
439 (next (vop-next vop
))
440 (block (vop-block vop
)))
442 (setf (vop-next prev
) next
)
443 (setf (ir2-block-start-vop block
) next
))
445 (setf (vop-prev next
) prev
)
446 (setf (ir2-block-last-vop block
) prev
)))
450 ;;; Return a list of N normal TNs of the specified primitive type.
451 (defun make-n-tns (n ptype
)
452 (declare (type unsigned-byte n
) (type primitive-type ptype
))
454 collect
(make-normal-tn ptype
)))
456 ;;; Return true if X and Y are packed in the same location, false otherwise.
457 ;;; This is false if either operand is constant.
458 (defun location= (x y
)
459 (declare (type tn x y
))
460 (and (eq (sc-sb (tn-sc x
)) (sc-sb (tn-sc y
)))
461 (eql (tn-offset x
) (tn-offset y
))
462 (not (or (eq (tn-kind x
) :constant
)
463 (eq (tn-kind y
) :constant
)))))
465 ;;; Return the value of an immediate constant TN.
467 (declare (type tn tn
))
468 (aver (eq (tn-kind tn
) :constant
))
469 (constant-value (tn-leaf tn
)))
471 (defun immediate-tn-p (tn)
472 (declare (type tn tn
))
473 (let ((leaf (tn-leaf tn
)))
474 ;; Leaves with KIND :CONSTANT can have NIL as the leaf if they
475 ;; represent load time values.
477 (eq (tn-kind tn
) :constant
)
478 (eq (immediate-constant-sc (constant-value leaf
))
479 (sc-number-or-lose 'sb
!vm
::immediate
)))))
481 ;;; Force TN to be allocated in a SC that doesn't need to be saved: an
482 ;;; unbounded non-save-p SC. We don't actually make it a real "restricted" TN,
483 ;;; but since we change the SC to an unbounded one, we should always succeed in
484 ;;; packing it in that SC.
485 (defun force-tn-to-stack (tn)
486 (declare (type tn tn
))
487 (let ((sc (tn-sc tn
)))
488 (unless (and (not (sc-save-p sc
))
489 (eq (sb-kind (sc-sb sc
)) :unbounded
))
490 (dolist (alt (sc-alternate-scs sc
)
491 (error "SC ~S has no :UNBOUNDED :SAVE-P NIL alternate SC."
493 (when (and (not (sc-save-p alt
))
494 (eq (sb-kind (sc-sb alt
)) :unbounded
))
495 (setf (tn-sc tn
) alt
)