1 ;;;; the x86 VM definition of operand loading/saving and the MOVE vop
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
14 (define-move-function (load-immediate 1) (vop x y)
16 (any-reg descriptor-reg))
17 (let ((val (tn-value x)))
22 (inst mov y (fixnumize val))))
26 (inst mov y (logior (ash (char-code val) type-bits)
29 (define-move-function (load-number 1) (vop x y)
30 ((immediate) (signed-reg unsigned-reg))
31 (inst mov y (tn-value x)))
33 (define-move-function (load-base-char 1) (vop x y)
34 ((immediate) (base-char-reg))
35 (inst mov y (char-code (tn-value x))))
37 (define-move-function (load-system-area-pointer 1) (vop x y)
38 ((immediate) (sap-reg))
39 (inst mov y (sap-int (tn-value x))))
41 (define-move-function (load-constant 5) (vop x y)
42 ((constant) (descriptor-reg any-reg))
45 (define-move-function (load-stack 5) (vop x y)
46 ((control-stack) (any-reg descriptor-reg)
47 (base-char-stack) (base-char-reg)
49 (signed-stack) (signed-reg)
50 (unsigned-stack) (unsigned-reg))
53 (define-move-function (store-stack 5) (vop x y)
54 ((any-reg descriptor-reg) (control-stack)
55 (base-char-reg) (base-char-stack)
57 (signed-reg) (signed-stack)
58 (unsigned-reg) (unsigned-stack))
63 (:args (x :scs (any-reg descriptor-reg immediate) :target y
64 :load-if (not (location= x y))))
65 (:results (y :scs (any-reg descriptor-reg)
67 (not (or (location= x y)
68 (and (sc-is x any-reg descriptor-reg immediate)
69 (sc-is y control-stack))))))
73 (if (and (sc-is x immediate)
74 (sc-is y any-reg descriptor-reg control-stack))
75 (let ((val (tn-value x)))
78 (if (and (zerop val) (sc-is y any-reg descriptor-reg))
80 (inst mov y (fixnumize val))))
82 (inst mov y (+ nil-value (static-symbol-offset val))))
84 (inst mov y (logior (ash (char-code val) type-bits)
88 (define-move-vop move :move
89 (any-reg descriptor-reg immediate)
90 (any-reg descriptor-reg))
92 ;;; Make Move the check VOP for T so that type check generation
93 ;;; doesn't think it is a hairy type. This also allows checking of a
94 ;;; few of the values in a continuation to fall out.
95 (primitive-type-vop move (:check) t)
97 ;;; The Move-Argument VOP is used for moving descriptor values into
98 ;;; another frame for argument or known value passing.
100 ;;; Note: It is not going to be possible to move a constant directly
101 ;;; to another frame, except if the destination is a register and in
102 ;;; this case the loading works out.
103 (define-vop (move-argument)
104 (:args (x :scs (any-reg descriptor-reg immediate) :target y
105 :load-if (not (and (sc-is y any-reg descriptor-reg)
106 (sc-is x control-stack))))
108 :load-if (not (sc-is y any-reg descriptor-reg))))
112 ((any-reg descriptor-reg)
113 (if (sc-is x immediate)
114 (let ((val (tn-value x)))
119 (inst mov y (fixnumize val))))
123 (inst mov y (logior (ash (char-code val) type-bits)
127 (if (sc-is x immediate)
128 (let ((val (tn-value x)))
129 (if (= (tn-offset fp) esp-offset)
133 (storew (fixnumize val) fp (tn-offset y)))
135 (storew (+ nil-value (static-symbol-offset val))
138 (storew (logior (ash (char-code val) type-bits)
144 (storew (fixnumize val) fp (- (1+ (tn-offset y)))))
146 (storew (+ nil-value (static-symbol-offset val))
147 fp (- (1+ (tn-offset y)))))
149 (storew (logior (ash (char-code val) type-bits)
151 fp (- (1+ (tn-offset y))))))))
152 (if (= (tn-offset fp) esp-offset)
154 (storew x fp (tn-offset y))
156 (storew x fp (- (1+ (tn-offset y))))))))))
158 (define-move-vop move-argument :move-argument
159 (any-reg descriptor-reg)
160 (any-reg descriptor-reg))
164 ;;; This VOP exists just to begin the lifetime of a TN that couldn't
165 ;;; be written legally due to a type error. An error is signalled
166 ;;; before this VOP is so we don't need to do anything (not that there
167 ;;; would be anything sensible to do anyway.)
168 (define-vop (illegal-move)
173 (:save-p :compute-only)
175 (error-call vop object-not-type-error x type)))
177 ;;;; moves and coercions
179 ;;; These MOVE-TO-WORD VOPs move a tagged integer to a raw full-word
180 ;;; representation. Similarly, the MOVE-FROM-WORD VOPs converts a raw
181 ;;; integer to a tagged bignum or fixnum.
183 ;;; Arg is a fixnum, so just shift it. We need a type restriction
184 ;;; because some possible arg SCs (control-stack) overlap with
185 ;;; possible bignum arg SCs.
186 (define-vop (move-to-word/fixnum)
187 (:args (x :scs (any-reg descriptor-reg) :target y
188 :load-if (not (location= x y))))
189 (:results (y :scs (signed-reg unsigned-reg)
190 :load-if (not (location= x y))))
191 (:arg-types tagged-num)
192 (:note "fixnum untagging")
196 (define-move-vop move-to-word/fixnum :move
197 (any-reg descriptor-reg) (signed-reg unsigned-reg))
199 ;;; Arg is a non-immediate constant, load it.
200 (define-vop (move-to-word-c)
201 (:args (x :scs (constant)))
202 (:results (y :scs (signed-reg unsigned-reg)))
203 (:note "constant load")
205 (inst mov y (tn-value x))))
206 (define-move-vop move-to-word-c :move
207 (constant) (signed-reg unsigned-reg))
210 ;;; Arg is a fixnum or bignum, figure out which and load if necessary.
211 (define-vop (move-to-word/integer)
212 (:args (x :scs (descriptor-reg) :target eax))
213 (:results (y :scs (signed-reg unsigned-reg)))
214 (:note "integer to untagged word coercion")
215 (:temporary (:sc unsigned-reg :offset eax-offset
216 :from (:argument 0) :to (:result 0) :target y) eax)
221 (loadw y eax bignum-digits-offset other-pointer-type)
227 (define-move-vop move-to-word/integer :move
228 (descriptor-reg) (signed-reg unsigned-reg))
231 ;;; Result is a fixnum, so we can just shift. We need the result type
232 ;;; restriction because of the control-stack ambiguity noted above.
233 (define-vop (move-from-word/fixnum)
234 (:args (x :scs (signed-reg unsigned-reg) :target y
235 :load-if (not (location= x y))))
236 (:results (y :scs (any-reg descriptor-reg)
237 :load-if (not (location= x y))))
238 (:result-types tagged-num)
239 (:note "fixnum tagging")
241 (cond ((and (sc-is x signed-reg unsigned-reg)
242 (not (location= x y)))
243 ;; Uses 7 bytes, but faster on the Pentium
244 (inst lea y (make-ea :dword :index x :scale 4)))
246 ;; Uses: If x is a reg 2 + 3; if x = y uses only 3 bytes
249 (define-move-vop move-from-word/fixnum :move
250 (signed-reg unsigned-reg) (any-reg descriptor-reg))
252 ;;; Result may be a bignum, so we have to check. Use a worst-case cost
253 ;;; to make sure people know they may be number consing.
255 ;;; KLUDGE: I assume this is suppressed in favor of the "faster inline
256 ;;; version" below. (See also mysterious comment "we don't want a VOP
257 ;;; on this one" on DEFINE-ASSEMBLY-ROUTINE (MOVE-FROM-SIGNED) in
258 ;;; "src/assembly/x86/alloc.lisp".) -- WHN 19990916
260 (define-vop (move-from-signed)
261 (:args (x :scs (signed-reg unsigned-reg) :target eax))
262 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)) eax)
263 (:temporary (:sc unsigned-reg :offset ebx-offset :to (:result 0) :target y)
265 (:temporary (:sc unsigned-reg :offset ecx-offset
266 :from (:argument 0) :to (:result 0)) ecx)
268 (:results (y :scs (any-reg descriptor-reg)))
269 (:note "signed word to integer coercion")
272 (inst call (make-fixup 'move-from-signed :assembly-routine))
274 ;;; Faster inline version,
275 ;;; KLUDGE: Do we really want the faster inline version? It's sorta big.
276 ;;; It is nice that it doesn't use any temporaries, though. -- WHN 19990916
277 (define-vop (move-from-signed)
278 (:args (x :scs (signed-reg unsigned-reg) :to :result))
279 (:results (y :scs (any-reg descriptor-reg) :from :argument))
280 (:note "signed word to integer coercion")
283 (aver (not (location= x y)))
284 (let ((bignum (gen-label))
292 ;; KLUDGE: The sequence above leaves a DESCRIPTOR-REG Y in a
293 ;; non-descriptor state for a while. Does that matter? Does it matter in
294 ;; GENGC but not in GENCGC? Is this written down anywhere?
297 ;; Also, the sequence above seems rather twisty. Why not something
298 ;; more obvious along the lines of
300 ;; inst tst x #xc0000000
301 ;; inst jmp :nz bignum
305 (assemble (*elsewhere*)
307 (with-fixed-allocation
308 (y bignum-type (+ bignum-digits-offset 1) node)
309 (storew x y bignum-digits-offset other-pointer-type))
311 (define-move-vop move-from-signed :move
312 (signed-reg) (descriptor-reg))
314 ;;; Check for fixnum, and possibly allocate one or two word bignum
315 ;;; result. Use a worst-case cost to make sure people know they may be
318 (define-vop (move-from-unsigned)
319 (:args (x :scs (signed-reg unsigned-reg) :target eax))
320 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)) eax)
321 (:temporary (:sc unsigned-reg :offset ebx-offset :to (:result 0) :target y)
323 (:temporary (:sc unsigned-reg :offset ecx-offset
324 :from (:argument 0) :to (:result 0)) ecx)
326 (:results (y :scs (any-reg descriptor-reg)))
327 (:note "unsigned word to integer coercion")
330 (inst call (make-fixup 'move-from-unsigned :assembly-routine))
332 ;;; Faster inline version.
333 ;;; KLUDGE: Do we really want the faster inline version? It seems awfully big..
334 ;;; If we really want speed, most likely it's only important in the non-consing
335 ;;; case, so how about about making the *ELSEWHERE* stuff into a subroutine? --
337 (define-vop (move-from-unsigned)
338 (:args (x :scs (signed-reg unsigned-reg) :to :save))
339 (:temporary (:sc unsigned-reg) alloc)
340 (:results (y :scs (any-reg descriptor-reg)))
342 (:note "unsigned word to integer coercion")
344 (aver (not (location= x y)))
345 (aver (not (location= x alloc)))
346 (aver (not (location= y alloc)))
347 (let ((bignum (gen-label))
349 (one-word-bignum (gen-label))
351 (inst test x #xe0000000)
352 (inst jmp :nz bignum)
354 (inst lea y (make-ea :dword :index x :scale 4)) ; Faster but bigger.
359 (assemble (*elsewhere*)
361 ;; Note: As on the mips port, space for a two word bignum is
362 ;; always allocated and the header size is set to either one
363 ;; or two words as appropriate.
364 (inst jmp :ns one-word-bignum)
366 (inst mov y (logior (ash (1- (+ bignum-digits-offset 2))
370 (emit-label one-word-bignum)
371 (inst mov y (logior (ash (1- (+ bignum-digits-offset 1))
376 (allocation alloc (pad-data-block (+ bignum-digits-offset 2)) node)
378 (inst lea y (make-ea :byte :base alloc :disp other-pointer-type))
379 (storew x y bignum-digits-offset other-pointer-type))
381 (define-move-vop move-from-unsigned :move
382 (unsigned-reg) (descriptor-reg))
384 ;;; Move untagged numbers.
385 (define-vop (word-move)
386 (:args (x :scs (signed-reg unsigned-reg) :target y
387 :load-if (not (location= x y))))
388 (:results (y :scs (signed-reg unsigned-reg)
390 (not (or (location= x y)
391 (and (sc-is x signed-reg unsigned-reg)
392 (sc-is y signed-stack unsigned-stack))))))
395 (:note "word integer move")
398 (define-move-vop word-move :move
399 (signed-reg unsigned-reg) (signed-reg unsigned-reg))
401 ;;; Move untagged number arguments/return-values.
402 (define-vop (move-word-argument)
403 (:args (x :scs (signed-reg unsigned-reg) :target y)
404 (fp :scs (any-reg) :load-if (not (sc-is y sap-reg))))
406 (:note "word integer argument move")
409 ((signed-reg unsigned-reg)
411 ((signed-stack unsigned-stack)
412 (if (= (tn-offset fp) esp-offset)
413 (storew x fp (tn-offset y)) ; c-call
414 (storew x fp (- (1+ (tn-offset y)))))))))
415 (define-move-vop move-word-argument :move-argument
416 (descriptor-reg any-reg signed-reg unsigned-reg) (signed-reg unsigned-reg))
418 ;;; Use standard MOVE-ARGUMENT and coercion to move an untagged number
419 ;;; to a descriptor passing location.
420 (define-move-vop move-argument :move-argument
421 (signed-reg unsigned-reg) (any-reg descriptor-reg))