9ef06419d73a38613a17c8c972089866604e152c
[sbcl.git] / src / compiler / ppc / move.lisp
1 ;;; Written by Rob MacLachlan.
2 ;;; SPARC conversion by William Lott.
3 ;;;
4 (in-package "SB!VM")
5
6
7 (define-move-fun (load-immediate 1) (vop x y)
8   ((null immediate zero)
9    (any-reg descriptor-reg))
10   (let ((val (tn-value x)))
11     (etypecase val
12       (integer
13        (inst lr y (fixnumize val)))
14       (null
15        (move y null-tn))
16       (symbol
17        (load-symbol y val))
18       (character
19        (inst lr y (logior (ash (char-code val) n-widetag-bits)
20                           base-char-widetag))))))
21
22 (define-move-fun (load-number 1) (vop x y)
23   ((immediate zero)
24    (signed-reg unsigned-reg))
25   (inst lr y (tn-value x)))
26
27 (define-move-fun (load-base-char 1) (vop x y)
28   ((immediate) (base-char-reg))
29   (inst li y (char-code (tn-value x))))
30
31 (define-move-fun (load-system-area-pointer 1) (vop x y)
32   ((immediate) (sap-reg))
33   (inst lr y (sap-int (tn-value x))))
34
35 (define-move-fun (load-constant 5) (vop x y)
36   ((constant) (descriptor-reg))
37   (loadw y code-tn (tn-offset x) other-pointer-lowtag))
38
39 (define-move-fun (load-stack 5) (vop x y)
40   ((control-stack) (any-reg descriptor-reg))
41   (load-stack-tn y x))
42
43 (define-move-fun (load-number-stack 5) (vop x y)
44   ((base-char-stack) (base-char-reg)
45    (sap-stack) (sap-reg)
46    (signed-stack) (signed-reg)
47    (unsigned-stack) (unsigned-reg))
48   (let ((nfp (current-nfp-tn vop)))
49     (loadw y nfp (tn-offset x))))
50
51 (define-move-fun (store-stack 5) (vop x y)
52   ((any-reg descriptor-reg) (control-stack))
53   (store-stack-tn y x))
54
55 (define-move-fun (store-number-stack 5) (vop x y)
56   ((base-char-reg) (base-char-stack)
57    (sap-reg) (sap-stack)
58    (signed-reg) (signed-stack)
59    (unsigned-reg) (unsigned-stack))
60   (let ((nfp (current-nfp-tn vop)))
61     (storew x nfp (tn-offset y))))
62
63 \f
64 ;;;; The Move VOP:
65 ;;;
66 (define-vop (move)
67   (:args (x :target y
68             :scs (any-reg descriptor-reg zero null)
69             :load-if (not (location= x y))))
70   (:results (y :scs (any-reg descriptor-reg)
71                :load-if (not (location= x y))))
72   (:effects)
73   (:affected)
74   (:generator 0
75     (move y x)))
76
77 (define-move-vop move :move
78   (any-reg descriptor-reg)
79   (any-reg descriptor-reg))
80
81 ;;; Make Move the check VOP for T so that type check generation doesn't think
82 ;;; it is a hairy type.  This also allows checking of a few of the values in a
83 ;;; continuation to fall out.
84 ;;;
85 (primitive-type-vop move (:check) t)
86
87 ;;;    The Move-Argument VOP is used for moving descriptor values into another
88 ;;; frame for argument or known value passing.
89 ;;;
90 (define-vop (move-arg)
91   (:args (x :target y
92             :scs (any-reg descriptor-reg zero null))
93          (fp :scs (any-reg)
94              :load-if (not (sc-is y any-reg descriptor-reg))))
95   (:results (y))
96   (:generator 0
97     (sc-case y
98       ((any-reg descriptor-reg)
99        (move y x))
100       (control-stack
101        (storew x fp (tn-offset y))))))
102 ;;;
103 (define-move-vop move-arg :move-arg
104   (any-reg descriptor-reg)
105   (any-reg descriptor-reg))
106
107
108 \f
109 ;;;; ILLEGAL-MOVE
110
111 ;;; This VOP exists just to begin the lifetime of a TN that couldn't be written
112 ;;; legally due to a type error.  An error is signalled before this VOP is
113 ;;; so we don't need to do anything (not that there would be anything sensible
114 ;;; to do anyway.)
115 ;;;
116 (define-vop (illegal-move)
117   (:args (x) (type))
118   (:results (y))
119   (:ignore y)
120   (:vop-var vop)
121   (:save-p :compute-only)
122   (:generator 666
123     (error-call vop object-not-type-error x type)))
124
125
126 \f
127 ;;;; Moves and coercions:
128
129 ;;; These MOVE-TO-WORD VOPs move a tagged integer to a raw full-word
130 ;;; representation.  Similarly, the MOVE-FROM-WORD VOPs converts a raw integer
131 ;;; to a tagged bignum or fixnum.
132
133 ;;; Arg is a fixnum, so just shift it.  We need a type restriction because some
134 ;;; possible arg SCs (control-stack) overlap with possible bignum arg SCs.
135 ;;;
136 (define-vop (move-to-word/fixnum)
137   (:args (x :scs (any-reg descriptor-reg)))
138   (:results (y :scs (signed-reg unsigned-reg)))
139   (:arg-types tagged-num)
140   (:note "fixnum untagging")
141   (:generator 1
142     (inst srawi y x 2)))
143 ;;;
144 (define-move-vop move-to-word/fixnum :move
145   (any-reg descriptor-reg) (signed-reg unsigned-reg))
146
147 ;;; Arg is a non-immediate constant, load it.
148 (define-vop (move-to-word-c)
149   (:args (x :scs (constant)))
150   (:results (y :scs (signed-reg unsigned-reg)))
151   (:note "constant load")
152   (:generator 1
153     (inst lr y (tn-value x))))
154 ;;;
155 (define-move-vop move-to-word-c :move
156   (constant) (signed-reg unsigned-reg))
157
158
159 ;;; Arg is a fixnum or bignum, figure out which and load if necessary.
160 (define-vop (move-to-word/integer)
161   (:args (x :scs (descriptor-reg)))
162   (:results (y :scs (signed-reg unsigned-reg)))
163   (:note "integer to untagged word coercion")
164   (:temporary (:scs (non-descriptor-reg)) temp)
165   (:generator 4
166     (let ((done (gen-label)))
167       (inst andi. temp x 3)
168       (sc-case y
169         (signed-reg
170          (inst srawi y x 2))
171         (unsigned-reg
172          (inst srwi y x 2)))
173       
174       (inst beq done)
175       (loadw y x bignum-digits-offset other-pointer-lowtag)
176       
177       (emit-label done))))
178 ;;;
179 (define-move-vop move-to-word/integer :move
180   (descriptor-reg) (signed-reg unsigned-reg))
181
182
183
184 ;;; Result is a fixnum, so we can just shift.  We need the result type
185 ;;; restriction because of the control-stack ambiguity noted above.
186 ;;;
187 (define-vop (move-from-word/fixnum)
188   (:args (x :scs (signed-reg unsigned-reg)))
189   (:results (y :scs (any-reg descriptor-reg)))
190   (:result-types tagged-num)
191   (:note "fixnum tagging")
192   (:generator 1
193     (inst slwi y x 2)))
194 ;;;
195 (define-move-vop move-from-word/fixnum :move
196   (signed-reg unsigned-reg) (any-reg descriptor-reg))
197
198
199 ;;; Result may be a bignum, so we have to check.  Use a worst-case cost to make
200 ;;; sure people know they may be number consing.
201 ;;;
202 (define-vop (move-from-signed)
203   (:args (arg :scs (signed-reg unsigned-reg) :target x))
204   (:results (y :scs (any-reg descriptor-reg)))
205   (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) x temp)
206   (:temporary (:sc non-descriptor-reg :offset nl3-offset) pa-flag)
207   (:note "signed word to integer coercion")
208   (:generator 20
209     (move x arg)
210     (let ((done (gen-label)))
211       (inst mtxer zero-tn)              ; clear sticky overflow bit in XER, CR0
212       (inst addo temp x x)              ; set XER OV if top two bits differ
213       (inst addo. temp temp temp)       ; set CR0 SO if any top three bits differ
214       (inst slwi y x 2)                 ; assume fixnum (tagged ok, maybe lost some high bits)
215       (inst bns done)
216       
217       (with-fixed-allocation (y pa-flag temp bignum-widetag (1+ bignum-digits-offset))
218         (storew x y bignum-digits-offset other-pointer-lowtag))
219       (emit-label done))))
220 ;;;
221 (define-move-vop move-from-signed :move
222   (signed-reg) (descriptor-reg))
223
224
225 ;;; Check for fixnum, and possibly allocate one or two word bignum result.  Use
226 ;;; a worst-case cost to make sure people know they may be number consing.
227 ;;;
228 (define-vop (move-from-unsigned)
229   (:args (arg :scs (signed-reg unsigned-reg) :target x))
230   (:results (y :scs (any-reg descriptor-reg)))
231   (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) x temp)
232   (:temporary (:sc non-descriptor-reg :offset nl3-offset) pa-flag)
233   (:note "unsigned word to integer coercion")
234   (:generator 20
235     (move x arg)
236     (let ((done (gen-label))
237           (one-word (gen-label))
238           (initial-alloc (pad-data-block (1+ bignum-digits-offset))))
239       (inst srawi. temp x 29)
240       (inst slwi y x 2)
241       (inst beq done)
242       
243       (pseudo-atomic (pa-flag :extra initial-alloc)
244         (inst cmpwi x 0)
245         (inst ori y alloc-tn other-pointer-lowtag)
246         (inst li temp (logior (ash 1 n-widetag-bits) bignum-widetag))
247         (inst bge one-word)
248         (inst addi alloc-tn alloc-tn
249               (- (pad-data-block (+ bignum-digits-offset 2))
250                  (pad-data-block (+ bignum-digits-offset 1))))
251         (inst li temp (logior (ash 2 n-widetag-bits) bignum-widetag))
252         (emit-label one-word)
253         (storew temp y 0 other-pointer-lowtag)
254         (storew x y bignum-digits-offset other-pointer-lowtag))
255       (emit-label done))))
256 ;;;
257 (define-move-vop move-from-unsigned :move
258   (unsigned-reg) (descriptor-reg))
259
260
261 ;;; Move untagged numbers.
262 ;;;
263 (define-vop (word-move)
264   (:args (x :target y
265             :scs (signed-reg unsigned-reg)
266             :load-if (not (location= x y))))
267   (:results (y :scs (signed-reg unsigned-reg)
268                :load-if (not (location= x y))))
269   (:effects)
270   (:affected)
271   (:note "word integer move")
272   (:generator 0
273     (move y x)))
274 ;;;
275 (define-move-vop word-move :move
276   (signed-reg unsigned-reg) (signed-reg unsigned-reg))
277
278
279 ;;; Move untagged number arguments/return-values.
280 ;;;
281 (define-vop (move-word-arg)
282   (:args (x :target y
283             :scs (signed-reg unsigned-reg))
284          (fp :scs (any-reg)
285              :load-if (not (sc-is y sap-reg))))
286   (:results (y))
287   (:note "word integer argument move")
288   (:generator 0
289     (sc-case y
290       ((signed-reg unsigned-reg)
291        (move y x))
292       ((signed-stack unsigned-stack)
293        (storew x fp (tn-offset y))))))
294 ;;;
295 (define-move-vop move-word-arg :move-arg
296   (descriptor-reg any-reg signed-reg unsigned-reg) (signed-reg unsigned-reg))
297
298
299 ;;; Use standard MOVE-ARGUMENT + coercion to move an untagged number to a
300 ;;; descriptor passing location.
301 ;;;
302 (define-move-vop move-arg :move-arg
303   (signed-reg unsigned-reg) (any-reg descriptor-reg))