Propagate (nth-value 1 truncate)+typep.
[sbcl.git] / src / compiler / arm64 / nlx.lisp
blobbdfee9110d34637994d9f51e30f42a024e0185cf
1 ;;;; the ARM definitions of VOPs used for non-local exit (throw,
2 ;;;; lexical exit, etc.)
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.
13 (in-package "SB-VM")
15 ;;; Make a TN for the argument count passing location for a
16 ;;; non-local entry.
17 (defun make-nlx-entry-arg-start-location ()
18 (make-wired-tn *fixnum-primitive-type* immediate-arg-scn r9-offset))
20 ;;; Save and restore dynamic environment.
21 (define-vop (current-stack-pointer)
22 (:results (res :scs (any-reg descriptor-reg)))
23 (:generator 1
24 (move res csp-tn)))
26 (define-vop (current-binding-pointer)
27 (:results (res :scs (any-reg descriptor-reg)))
28 (:generator 1
29 (load-binding-stack-pointer res)))
31 (define-vop (current-nsp)
32 (:results (res :scs (any-reg descriptor-reg)))
33 (:generator 1
34 (inst mov-sp res nsp-tn)))
36 (define-vop (set-nsp)
37 (:args (nsp :scs (any-reg descriptor-reg)))
38 (:generator 1
39 (inst mov-sp nsp-tn nsp)))
41 ;;;; Unwind block hackery:
43 ;;; Compute the address of the catch block from its TN, then store into the
44 ;;; block the current Fp, Env, Unwind-Protect, and the entry PC.
45 ;;;
46 (define-vop (make-unwind-block)
47 (:args (tn))
48 (:info entry-label)
49 (:results (block :scs (any-reg)))
50 (:temporary (:scs (descriptor-reg)) temp)
51 (:vop-var vop)
52 (:generator 22
53 (inst add block cfp-tn (add-sub-immediate (tn-byte-offset tn)))
54 (load-tl-symbol-value temp *current-unwind-protect-block*)
55 (storew-pair temp unwind-block-uwp-slot cfp-tn unwind-block-cfp-slot block)
56 (inst adr temp entry-label)
57 (storew temp block unwind-block-entry-pc-slot)
58 #+sb-thread
59 (loadw-pair
60 temp (/ (info :variable :wired-tls '*binding-stack-pointer*) n-word-bytes)
61 tmp-tn (/ (info :variable :wired-tls '*current-catch-block*) n-word-bytes)
62 thread-tn)
63 #-sb-thread
64 (progn
65 (load-binding-stack-pointer temp)
66 (load-tl-symbol-value tmp-tn *current-catch-block*))
67 (storew-pair temp unwind-block-bsp-slot tmp-tn unwind-block-current-catch-slot block)
68 (inst mov-sp temp nsp-tn)
69 (let ((nfp (current-nfp-tn vop)))
70 (if nfp
71 (storew-pair nfp unwind-block-nfp-slot
72 temp unwind-block-nsp-slot
73 block)
74 (storew temp block unwind-block-nsp-slot)))))
76 ;;; Like Make-Unwind-Block, except that we also store in the specified tag, and
77 ;;; link the block into the Current-Catch list.
78 ;;;
79 (define-vop (make-catch-block)
80 (:args (tn) (tag :scs (any-reg descriptor-reg)))
81 (:info entry-label)
82 (:results (block :scs (any-reg)))
83 (:temporary (:scs (descriptor-reg)) temp)
84 (:vop-var vop)
85 (:generator 44
86 (inst add block cfp-tn (add-sub-immediate (tn-byte-offset tn)))
87 (load-tl-symbol-value temp *current-unwind-protect-block*)
88 (storew-pair temp catch-block-uwp-slot cfp-tn catch-block-cfp-slot block)
89 (inst adr temp entry-label)
90 (storew temp block catch-block-entry-pc-slot)
92 #+sb-thread
93 (loadw-pair
94 temp (/ (info :variable :wired-tls '*binding-stack-pointer*) n-word-bytes)
95 tmp-tn (/ (info :variable :wired-tls '*current-catch-block*) n-word-bytes)
96 thread-tn)
97 #-sb-thread
98 (progn
99 (load-binding-stack-pointer temp)
100 (load-tl-symbol-value tmp-tn *current-catch-block*))
101 (storew-pair tmp-tn catch-block-previous-catch-slot tag catch-block-tag-slot block)
102 (storew temp block catch-block-bsp-slot)
103 (inst mov-sp temp nsp-tn)
104 (let ((nfp (current-nfp-tn vop)))
105 (if nfp
106 (storew-pair nfp unwind-block-nfp-slot
107 temp unwind-block-nsp-slot
108 block)
109 (storew temp block unwind-block-nsp-slot)))
110 (store-tl-symbol-value block *current-catch-block*)))
112 ;;; Just set the current unwind-protect to UWP. This
113 ;;; instantiates an unwind block as an unwind-protect.
114 (define-vop (set-unwind-protect)
115 (:args (uwp :scs (any-reg)))
116 (:generator 7
117 (store-tl-symbol-value uwp *current-unwind-protect-block*)))
119 (define-vop (%catch-breakup)
120 (:args (current-block))
121 (:ignore current-block)
122 (:temporary (:scs (any-reg)) block)
123 (:policy :fast-safe)
124 (:generator 17
125 (load-tl-symbol-value block *current-catch-block*)
126 (loadw block block catch-block-previous-catch-slot)
127 (store-tl-symbol-value block *current-catch-block*)))
129 (define-vop (%unwind-protect-breakup)
130 (:args (current-block))
131 (:ignore current-block)
132 (:temporary (:scs (any-reg)) block)
133 (:policy :fast-safe)
134 (:generator 17
135 (load-tl-symbol-value block *current-unwind-protect-block*)
136 (loadw block block unwind-block-uwp-slot)
137 (store-tl-symbol-value block *current-unwind-protect-block*)))
139 ;;;; NLX entry VOPs:
141 (define-vop (nlx-entry)
142 (:args (sp) ; Note: we can't list an sc-restriction, 'cause any load vops
143 ; would be inserted before the label.
144 (start)
145 (count))
146 (:results (values :more t :from :load))
147 (:temporary (:scs (descriptor-reg)) move-temp)
148 (:info label nvals)
149 (:save-p :force-to-stack)
150 (:vop-var vop)
151 (:generator 30
152 (emit-label label)
153 (note-this-location vop :non-local-entry)
154 (cond ((zerop nvals))
155 ((= nvals 1)
156 (assemble ()
157 (move (tn-ref-tn values) null-tn)
158 (inst cbz count zero)
159 (loadw (tn-ref-tn values) start)
160 ZERO))
162 (do ((i 0 (1+ i))
163 (tn-ref values (tn-ref-across tn-ref)))
164 ((null tn-ref))
165 (let ((tn (tn-ref-tn tn-ref)))
166 (inst subs count count (fixnumize 1))
167 (sc-case tn
168 ((descriptor-reg any-reg)
169 (assemble ()
170 (move tn null-tn)
171 (inst b :lt LESS-THAN)
172 (loadw tn start i)
173 LESS-THAN))
174 (control-stack
175 (assemble ()
176 (move move-temp null-tn)
177 (inst b :lt LESS-THAN)
178 (loadw move-temp start i)
179 LESS-THAN
180 (store-stack-tn tn move-temp))))))))
181 (load-stack-tn csp-tn sp)))
183 (define-vop (nlx-entry-single)
184 (:args (sp)
185 (value))
186 (:results (res :from :load))
187 (:info label)
188 (:save-p :force-to-stack)
189 (:vop-var vop)
190 (:generator 30
191 (emit-label label)
192 (note-this-location vop :non-local-entry)
193 (inst mov res value)
194 (load-stack-tn csp-tn sp)))
196 (define-vop (nlx-entry-multiple)
197 (:args (top :target result
198 :scs (any-reg))
199 (src :to :save)
200 (count :target count-words))
201 (:info label)
202 (:temporary (:scs (any-reg)) dst)
203 (:temporary (:scs (descriptor-reg)) temp)
204 (:temporary (:scs (descriptor-reg)) count-words)
205 (:results (result :scs (any-reg) :from (:argument 0))
206 (num :scs (any-reg) :from (:argument 0)))
207 (:save-p :force-to-stack)
208 (:vop-var vop)
209 (:before-load
210 (emit-label label)
211 (note-this-location vop :non-local-entry))
212 (:generator 30
214 ;; Setup results, and test for the zero value case.
215 (if (eq (tn-kind result) :unused)
216 (setf result top)
217 (move result top))
218 (when (eq (tn-kind num) :unused)
219 (setf num tmp-tn))
220 (inst mov num 0)
221 ;; Shift and check for zero in one go
222 (inst adds count-words zr-tn (lsl count (- word-shift n-fixnum-tag-bits)))
223 (inst b :eq DONE)
225 ;; Compute dst as one slot down from result, because we inc the index
226 ;; before we use it.
227 (inst sub dst result n-word-bytes)
229 ;; Copy stuff down the stack.
230 LOOP
231 (inst ldr temp (@ src num))
232 (inst add num num n-word-bytes)
233 (inst cmp num count-words)
234 (inst str temp (@ dst num))
235 (inst b :ne LOOP)
237 ;; Reset the CSP.
238 DONE
239 (inst add csp-tn result num)
240 (unless (eq (tn-kind num) :unused)
241 (inst lsr num num (- word-shift n-fixnum-tag-bits)))))
243 ;;; This VOP is just to force the TNs used in the cleanup onto the stack.
245 (define-vop (uwp-entry)
246 (:info label)
247 (:save-p :force-to-stack)
248 (:vop-var vop)
249 (:generator 0
250 (emit-label label)
251 (note-this-location vop :non-local-entry)))
253 (define-vop (uwp-entry-block)
254 (:info label)
255 (:save-p :force-to-stack)
256 (:results (block))
257 (:vop-var vop)
258 (:generator 0
259 (emit-label label)
260 (note-this-location vop :non-local-entry)
261 ;; Get the block saved in UNWIND
262 (inst ldr block (@ csp-tn (* -4 n-word-bytes)))))
264 #+unwind-to-frame-and-call-vop
265 (define-vop (unwind-to-frame-and-call)
266 (:args (ofp :scs (descriptor-reg))
267 (uwp :scs (descriptor-reg))
268 (function :scs (descriptor-reg) :to :load :target saved-function)
269 (bsp :scs (any-reg descriptor-reg))
270 (nsp :scs (any-reg descriptor-reg))
271 (catch-block :scs (any-reg descriptor-reg)))
272 (:arg-types system-area-pointer system-area-pointer t t t t)
273 (:temporary (:sc unsigned-reg) temp)
274 (:temporary (:sc descriptor-reg :offset r9-offset) saved-function)
275 (:temporary (:sc unsigned-reg :offset r0-offset) block)
276 (:temporary (:sc descriptor-reg :offset lexenv-offset) lexenv)
277 (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr)
278 (:temporary (:sc descriptor-reg :offset nargs-offset) nargs)
279 (:vop-var vop)
280 (:generator 22
281 (let ((entry-label (gen-label)))
282 ;; Store the function into a non-stack location, since we'll be
283 ;; unwinding the stack and destroying register contents before we
284 ;; use it. It turns out that R9 is preserved as part of the
285 ;; normal multiple-value handling of an unwind, so use that.
286 (move saved-function function)
288 ;; Allocate space for magic UWP block.
289 (move block csp-tn)
290 (inst add csp-tn block (* unwind-block-size n-word-bytes))
292 ;; Set up magic catch / UWP block.
294 (loadw temp uwp sap-pointer-slot other-pointer-lowtag)
295 (storew temp block unwind-block-uwp-slot)
296 (loadw temp ofp sap-pointer-slot other-pointer-lowtag)
297 (storew temp block unwind-block-cfp-slot)
298 (storew bsp block unwind-block-bsp-slot)
299 (storew nsp block unwind-block-nsp-slot)
300 (storew catch-block block unwind-block-current-catch-slot)
302 (inst adr temp entry-label)
303 (storew temp block catch-block-entry-pc-slot)
305 ;; Run any required UWPs.
306 (invoke-asm-routine 'unwind tmp-tn :tail t)
308 (emit-label ENTRY-LABEL)
309 (inst mov nargs 0)
311 (move lexenv saved-function)
313 (loadw lr lexenv closure-fun-slot fun-pointer-lowtag)
314 (lisp-jump lr))))