1.0.31.31: SATISFIES cannot refer to local functions
[sbcl.git] / src / compiler / ppc / nlx.lisp
1 ;;;; the PPC definitions of VOPs used for non-local exit (throw,
2 ;;;; lexical exit, etc.)
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!VM")
14
15 ;;; Make an environment-live stack TN for saving the SP for NLX entry.
16 (!def-vm-support-routine make-nlx-sp-tn (env)
17   (physenv-live-tn
18    (make-representation-tn *fixnum-primitive-type* immediate-arg-scn)
19    env))
20
21 ;;; Make a TN for the argument count passing location for a
22 ;;; non-local entry.
23 (!def-vm-support-routine make-nlx-entry-arg-start-location ()
24   (make-wired-tn *fixnum-primitive-type* immediate-arg-scn ocfp-offset))
25
26 \f
27 ;;; These VOPs are used in the reentered function to restore the
28 ;;; appropriate dynamic environment. Currently we only save the
29 ;;; CURRENT-CATCH and binding stack pointer. We don't need to
30 ;;; save/restore the current unwind-protect, since UNWIND-PROTECTs are
31 ;;; implicitly processed during unwinding. If there were any
32 ;;; additional stacks, then this would be the place to restore the top
33 ;;; pointers.
34
35 (define-vop (save-dynamic-state)
36   (:results (catch :scs (descriptor-reg))
37             (nfp :scs (descriptor-reg))
38             (nsp :scs (descriptor-reg)))
39   (:vop-var vop)
40   (:generator 13
41     (load-symbol-value catch *current-catch-block*)
42     (let ((cur-nfp (current-nfp-tn vop)))
43       (when cur-nfp
44         (move nfp cur-nfp)))
45     (move nsp nsp-tn)))
46
47 (define-vop (restore-dynamic-state)
48   (:args (catch :scs (descriptor-reg))
49          (nfp :scs (descriptor-reg))
50          (nsp :scs (descriptor-reg)))
51   (:vop-var vop)
52   (:generator 10
53     (store-symbol-value catch *current-catch-block*)
54     (let ((cur-nfp (current-nfp-tn vop)))
55       (when cur-nfp
56         (move cur-nfp nfp)))
57     (move nsp-tn nsp)))
58
59 (define-vop (current-stack-pointer)
60   (:results (res :scs (any-reg descriptor-reg)))
61   (:generator 1
62     (move res csp-tn)))
63
64 (define-vop (current-binding-pointer)
65   (:results (res :scs (any-reg descriptor-reg)))
66   (:generator 1
67     (move res bsp-tn)))
68
69
70 \f
71 ;;;; Unwind block hackery:
72
73 ;;; Compute the address of the catch block from its TN, then store into the
74 ;;; block the current Fp, Env, Unwind-Protect, and the entry PC.
75 ;;;
76 (define-vop (make-unwind-block)
77   (:args (tn))
78   (:info entry-label)
79   (:results (block :scs (any-reg)))
80   (:temporary (:scs (descriptor-reg)) temp)
81   (:temporary (:scs (non-descriptor-reg)) ndescr)
82   (:generator 22
83     (inst addi block cfp-tn (* (tn-offset tn) n-word-bytes))
84     (load-symbol-value temp *current-unwind-protect-block*)
85     (storew temp block unwind-block-current-uwp-slot)
86     (storew cfp-tn block unwind-block-current-cont-slot)
87     (storew code-tn block unwind-block-current-code-slot)
88     (inst compute-lra-from-code temp code-tn entry-label ndescr)
89     (storew temp block catch-block-entry-pc-slot)))
90
91
92 ;;; Like Make-Unwind-Block, except that we also store in the specified tag, and
93 ;;; link the block into the Current-Catch list.
94 ;;;
95 (define-vop (make-catch-block)
96   (:args (tn)
97          (tag :scs (any-reg descriptor-reg)))
98   (:info entry-label)
99   (:results (block :scs (any-reg)))
100   (:temporary (:scs (descriptor-reg)) temp)
101   (:temporary (:scs (descriptor-reg) :target block :to (:result 0)) result)
102   (:temporary (:scs (non-descriptor-reg)) ndescr)
103   (:generator 44
104     (inst addi result cfp-tn (* (tn-offset tn) n-word-bytes))
105     (load-symbol-value temp *current-unwind-protect-block*)
106     (storew temp result catch-block-current-uwp-slot)
107     (storew cfp-tn result catch-block-current-cont-slot)
108     (storew code-tn result catch-block-current-code-slot)
109     (inst compute-lra-from-code temp code-tn entry-label ndescr)
110     (storew temp result catch-block-entry-pc-slot)
111
112     (storew tag result catch-block-tag-slot)
113     (load-symbol-value temp *current-catch-block*)
114     (storew temp result catch-block-previous-catch-slot)
115     (store-symbol-value result *current-catch-block*)
116
117     (move block result)))
118
119
120 ;;; Just set the current unwind-protect to TN's address.  This instantiates an
121 ;;; unwind block as an unwind-protect.
122 ;;;
123 (define-vop (set-unwind-protect)
124   (:args (tn))
125   (:temporary (:scs (descriptor-reg)) new-uwp)
126   (:generator 7
127     (inst addi new-uwp cfp-tn (* (tn-offset tn) n-word-bytes))
128     (store-symbol-value new-uwp *current-unwind-protect-block*)))
129
130
131 (define-vop (unlink-catch-block)
132   (:temporary (:scs (any-reg)) block)
133   (:policy :fast-safe)
134   (:translate %catch-breakup)
135   (:generator 17
136     (load-symbol-value block *current-catch-block*)
137     (loadw block block catch-block-previous-catch-slot)
138     (store-symbol-value block *current-catch-block*)))
139
140 (define-vop (unlink-unwind-protect)
141   (:temporary (:scs (any-reg)) block)
142   (:policy :fast-safe)
143   (:translate %unwind-protect-breakup)
144   (:generator 17
145     (load-symbol-value block *current-unwind-protect-block*)
146     (loadw block block unwind-block-current-uwp-slot)
147     (store-symbol-value block *current-unwind-protect-block*)))
148
149 \f
150 ;;;; NLX entry VOPs:
151
152
153 (define-vop (nlx-entry)
154   (:args (sp) ; Note: we can't list an sc-restriction, 'cause any load vops
155               ; would be inserted before the LRA.
156          (start)
157          (count))
158   (:results (values :more t))
159   (:temporary (:scs (descriptor-reg)) move-temp)
160   (:info label nvals)
161   (:save-p :force-to-stack)
162   (:vop-var vop)
163   (:generator 30
164     (emit-return-pc label)
165     (note-this-location vop :non-local-entry)
166     (cond ((zerop nvals))
167           ((= nvals 1)
168            (let ((no-values (gen-label)))
169              (inst cmpwi count 0)
170              (move (tn-ref-tn values) null-tn)
171              (inst beq no-values)
172              (loadw (tn-ref-tn values) start)
173              (emit-label no-values)))
174           (t
175            (collect ((defaults))
176              (inst addic. count count (- (fixnumize 1)))
177              (do ((i 0 (1+ i))
178                   (tn-ref values (tn-ref-across tn-ref)))
179                  ((null tn-ref))
180                (let ((default-lab (gen-label))
181                      (tn (tn-ref-tn tn-ref)))
182                  (defaults (cons default-lab tn))
183
184                  (inst subi count count (fixnumize 1))
185                  (inst blt default-lab)
186                  (sc-case tn
187                           ((descriptor-reg any-reg)
188                            (loadw tn start i))
189                           (control-stack
190                            (loadw move-temp start i)
191                            (store-stack-tn tn move-temp)))
192                  (inst cmpwi count 0)))
193
194              (let ((defaulting-done (gen-label)))
195
196                (emit-label defaulting-done)
197
198                (assemble (*elsewhere*)
199                  (dolist (def (defaults))
200                    (emit-label (car def))
201                    (let ((tn (cdr def)))
202                      (sc-case tn
203                               ((descriptor-reg any-reg)
204                                (move tn null-tn))
205                               (control-stack
206                                (store-stack-tn tn null-tn)))))
207                  (inst b defaulting-done))))))
208     (load-stack-tn csp-tn sp)))
209
210
211 (define-vop (nlx-entry-multiple)
212   (:args (top :target result) (src) (count))
213   ;; Again, no SC restrictions for the args, 'cause the loading would
214   ;; happen before the entry label.
215   (:info label)
216   (:temporary (:scs (any-reg)) dst)
217   (:temporary (:scs (descriptor-reg)) temp)
218   (:results (result :scs (any-reg) :from (:argument 0))
219             (num :scs (any-reg) :from (:argument 0)))
220   (:save-p :force-to-stack)
221   (:vop-var vop)
222   (:generator 30
223     (emit-return-pc label)
224     (note-this-location vop :non-local-entry)
225     (let ((loop (gen-label))
226           (done (gen-label)))
227
228       ;; Setup results, and test for the zero value case.
229       (load-stack-tn result top)
230       (inst cmpwi count 0)
231       (inst li num 0)
232       (inst beq done)
233
234       ;; Compute dst as one slot down from result, because we inc the index
235       ;; before we use it.
236       (inst subi dst result 4)
237
238       ;; Copy stuff down the stack.
239       (emit-label loop)
240       (inst lwzx temp src num)
241       (inst addi num num (fixnumize 1))
242       (inst cmpw num count)
243       (inst stwx temp dst num)
244       (inst bne loop)
245
246       ;; Reset the CSP.
247       (emit-label done)
248       (inst add csp-tn result num))))
249
250
251 ;;; This VOP is just to force the TNs used in the cleanup onto the stack.
252 ;;;
253 (define-vop (uwp-entry)
254   (:info label)
255   (:save-p :force-to-stack)
256   (:results (block) (start) (count))
257   (:ignore block start count)
258   (:vop-var vop)
259   (:generator 0
260     (emit-return-pc label)
261     (note-this-location vop :non-local-entry)))
262