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]) Declaration* Form*
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
)))
28 (do ((,tn
(ir2-component-restricted-tns ,n-component
) (tn-next ,tn
)))
31 (do ((,tn
(ir2-component-wired-tns ,n-component
) (tn-next ,tn
)))
36 (defun set-ir2-physenv-live-tns (value instance
)
37 (setf (ir2-physenv-live-tns instance
) value
))
39 (defun set-ir2-physenv-debug-live-tns (value instance
)
40 (setf (ir2-physenv-debug-live-tns instance
) value
))
42 (defun set-ir2-component-alias-tns (value instance
)
43 (setf (ir2-component-alias-tns instance
) value
))
45 (defun set-ir2-component-normal-tns (value instance
)
46 (setf (ir2-component-normal-tns instance
) value
))
48 (defun set-ir2-component-restricted-tns (value instance
)
49 (setf (ir2-component-restricted-tns instance
) value
))
51 (defun set-ir2-component-wired-tns (value instance
)
52 (setf (ir2-component-wired-tns instance
) value
))
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
)
64 (do ((tn (funcall getter
2comp
) (tn-next tn
)))
68 (and (eq (tn-kind tn
) :specified-save
)
69 (used-p (tn-save-tn tn
))))
72 (delete-1 tn prev setter
))))))
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
)
79 (setf (tn-next prev
) (tn-next tn
))
80 (funcall setter
(tn-next tn
) 2comp
))
81 (setf (tn-offset tn
) nil
)
85 #'ir2-physenv-live-tns
86 #'set-ir2-physenv-live-tns
))
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
)))
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
)))
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
))
118 (push-in tn-next res
(ir2-component-normal-tns component
))
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
))
127 (svref *backend-sc-numbers
* scn
))))
128 (push-in tn-next res
(ir2-component-normal-tns component
))
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
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
))
141 (svref *backend-sc-numbers
* scn
))))
142 (setf (tn-offset res
) offset
)
143 (push-in tn-next res
(ir2-component-wired-tns component
))
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
))
153 (svref *backend-sc-numbers
* scn
))))
154 (push-in tn-next res
(ir2-component-restricted-tns component
))
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
)))
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
)))
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
*)))
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
)
195 (ir2-component-specified-save-tns
196 (component-info *component-being-compiled
*)))
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
207 (boxed-immediate-sc-p immed
)))))
209 ;; CONSTANT-TN uses two caches, one for boxed and one for unboxed uses.
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
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
)))
219 (let* ((component (component-info *component-being-compiled
*))
220 (sc (svref *backend-sc-numbers
*
223 (sc-number-or-lose 'constant
))))
224 (res (make-tn 0 :constant
(primitive-type (leaf-type constant
)) sc
)))
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
)
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
))
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
)
252 (ir2-component-alias-tns component
))
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
*))
263 *backend-t-primitive-type
*
264 (svref *backend-sc-numbers
*
265 (sc-number-or-lose 'constant
))))
266 (constants (ir2-component-constants component
)))
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
)
277 (equal (cdr entry
) info
))))
278 (setf (tn-offset res
) i
)
281 (push-in tn-next res
(ir2-component-constant-tns component
))
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
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
)))
294 (push-in tn-ref-next res
(tn-writes tn
))
295 (push-in tn-ref-next res
(tn-reads tn
)))
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
))
305 (let* ((first (reference-tn (first tns
) write-p
))
307 (dolist (tn (rest tns
))
308 (let ((res (reference-tn tn write-p
)))
309 (setf (tn-ref-across prev
) res
)
311 (setf (tn-ref-across prev
) more
)
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
))
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
))
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
)))
334 ;;;; miscellaneous utilities
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
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 (emit-and-insert-vop node block template arg result before
)))
348 ;;; like EMIT-MOVE-TEMPLATE, except that we pass in INFO args too
349 (defun emit-load-template (node block template x y info
&optional before
)
350 (declare (type node node
) (type ir2-block block
)
351 (type template template
) (type tn x y
))
352 (let ((arg (reference-tn x nil
))
353 (result (reference-tn y t
)))
354 (emit-and-insert-vop node block template arg result before info
)))
356 ;;; like EMIT-MOVE-TEMPLATE, except that the VOP takes two args
357 (defun emit-move-arg-template (node block template x f y
&optional before
)
358 (declare (type node node
) (type ir2-block block
)
359 (type template template
) (type tn x f y
))
360 (let ((x-ref (reference-tn x nil
))
361 (f-ref (reference-tn f nil
))
362 (y-ref (reference-tn y t
)))
363 (setf (tn-ref-across x-ref
) f-ref
)
364 (emit-and-insert-vop node block template x-ref y-ref before
)))
366 ;;; like EMIT-MOVE-TEMPLATE, except that the VOP takes no args
367 (defun emit-context-template (node block template y
&optional before
)
368 (declare (type node node
) (type ir2-block block
)
369 (type template template
) (type tn y
))
370 (let ((y-ref (reference-tn y t
)))
371 (emit-and-insert-vop node block template nil y-ref before
)))
373 ;;; Return the label marking the start of Block, assigning one if necessary.
374 (defun block-label (block)
375 (declare (type cblock block
))
376 (let ((2block (block-info block
)))
377 (or (ir2-block-%label
2block
)
378 (setf (ir2-block-%label
2block
) (gen-label)))))
379 (defun block-trampoline (block)
380 (declare (type cblock block
))
381 (let ((2block (block-info block
)))
382 (or (ir2-block-%trampoline-label
2block
)
383 (setf (ir2-block-%trampoline-label
2block
) (gen-label)))))
385 ;;; Return true if Block is emitted immediately after the block ended by Node.
386 (defun drop-thru-p (node block
)
387 (declare (type node node
) (type cblock block
))
388 (let ((next-block (ir2-block-next (block-info (node-block node
)))))
389 (aver (eq node
(block-last (node-block node
))))
390 (eq next-block
(block-info block
))))
391 (defun register-drop-thru (block)
392 (declare (type cblock block
))
393 (let ((2block (block-info block
)))
394 (setf (ir2-block-dropped-thru-to 2block
) t
))
397 ;;; Insert a VOP into BLOCK, before the specified
398 ;;; BEFORE VOP. If BEFORE is NIL, insert at the end.
399 (defun insert-vop (vop block before
)
400 (declare (type vop vop
) (type ir2-block block
)
401 (type (or vop null
) before
))
403 (let ((prev (vop-prev before
)))
404 (setf (vop-prev vop
) prev
)
406 (setf (vop-next prev
) vop
)
407 (setf (ir2-block-start-vop block
) vop
))
408 (setf (vop-next vop
) before
)
409 (setf (vop-prev before
) vop
))
410 (let ((current (ir2-block-last-vop block
)))
411 (setf (vop-prev vop
) current
)
412 (setf (ir2-block-last-vop block
) vop
)
414 (setf (vop-next current
) vop
)
415 (setf (ir2-block-start-vop block
) vop
))))
418 (defun emit-and-insert-vop (node block template arg result before
420 (let ((vop (emit-vop node block template arg result info
)))
421 (insert-vop vop block before
)
424 ;;; Delete all of the TN-REFs associated with VOP and remove VOP from the IR2.
425 (defun delete-vop (vop)
426 (declare (type vop vop
))
427 (do ((ref (vop-refs vop
) (tn-ref-next-ref ref
)))
431 (let ((prev (vop-prev vop
))
432 (next (vop-next vop
))
433 (block (vop-block vop
)))
435 (setf (vop-next prev
) next
)
436 (setf (ir2-block-start-vop block
) next
))
438 (setf (vop-prev next
) prev
)
439 (setf (ir2-block-last-vop block
) prev
)))
443 ;;; Return a list of N normal TNs of the specified primitive type.
444 (defun make-n-tns (n ptype
)
445 (declare (type unsigned-byte n
) (type primitive-type ptype
))
447 collect
(make-normal-tn ptype
)))
449 ;;; Return true if X and Y are packed in the same location, false otherwise.
450 ;;; This is false if either operand is constant.
451 (defun location= (x y
)
452 (declare (type tn x y
))
453 (and (eq (sc-sb (tn-sc x
)) (sc-sb (tn-sc y
)))
454 (eql (tn-offset x
) (tn-offset y
))
455 (not (or (eq (tn-kind x
) :constant
)
456 (eq (tn-kind y
) :constant
)))))
458 ;;; Return the value of an immediate constant TN.
460 (declare (type tn tn
))
461 (aver (eq (tn-kind tn
) :constant
))
462 (constant-value (tn-leaf tn
)))
464 (defun immediate-tn-p (tn)
465 (declare (type tn tn
))
466 (let ((leaf (tn-leaf tn
)))
467 ;; Leaves with KIND :CONSTANT can have NIL as the leaf if they
468 ;; represent load time values.
470 (eq (tn-kind tn
) :constant
)
471 (eq (immediate-constant-sc (constant-value leaf
))
472 (sc-number-or-lose 'sb
!vm
::immediate
)))))
474 ;;; Force TN to be allocated in a SC that doesn't need to be saved: an
475 ;;; unbounded non-save-p SC. We don't actually make it a real "restricted" TN,
476 ;;; but since we change the SC to an unbounded one, we should always succeed in
477 ;;; packing it in that SC.
478 (defun force-tn-to-stack (tn)
479 (declare (type tn tn
))
480 (let ((sc (tn-sc tn
)))
481 (unless (and (not (sc-save-p sc
))
482 (eq (sb-kind (sc-sb sc
)) :unbounded
))
483 (dolist (alt (sc-alternate-scs sc
)
484 (error "SC ~S has no :UNBOUNDED :SAVE-P NIL alternate SC."
486 (when (and (not (sc-save-p alt
))
487 (eq (sb-kind (sc-sb alt
)) :unbounded
))
488 (setf (tn-sc tn
) alt
)