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-fun (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) n-widetag-bits)
27 character-widetag))))))
29 (define-move-fun (load-number 1) (vop x y)
30 ((immediate) (signed-reg unsigned-reg))
31 (inst mov y (tn-value x)))
33 (define-move-fun (load-character 1) (vop x y)
34 ((immediate) (character-reg))
35 (inst mov y (char-code (tn-value x))))
37 (define-move-fun (load-system-area-pointer 1) (vop x y)
38 ((immediate) (sap-reg))
39 (inst mov y (sap-int (tn-value x))))
41 (define-move-fun (load-constant 5) (vop x y)
42 ((constant) (descriptor-reg any-reg))
45 (define-move-fun (load-stack 5) (vop x y)
46 ((control-stack) (any-reg descriptor-reg)
47 (character-stack) (character-reg)
49 (signed-stack) (signed-reg)
50 (unsigned-stack) (unsigned-reg))
53 (define-move-fun (store-stack 5) (vop x y)
54 ((any-reg descriptor-reg) (control-stack)
55 (character-reg) (character-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) n-widetag-bits)
85 character-widetag)))))
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-ARG 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-arg)
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) n-widetag-bits)
124 character-widetag)))))
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) n-widetag-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) n-widetag-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-arg :move-arg
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-lowtag)
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
294 ;; matter in GENGC but not in GENCGC? Is this written down
298 ;; Also, the sequence above seems rather twisty. Why not something
299 ;; more obvious along the lines of
301 ;; inst tst x #xc0000000
302 ;; inst jmp :nz bignum
306 (assemble (*elsewhere*)
308 (with-fixed-allocation
309 (y bignum-widetag (+ bignum-digits-offset 1) node)
310 (storew x y bignum-digits-offset other-pointer-lowtag))
312 (define-move-vop move-from-signed :move
313 (signed-reg) (descriptor-reg))
315 ;;; Check for fixnum, and possibly allocate one or two word bignum
316 ;;; result. Use a worst-case cost to make sure people know they may be
319 (define-vop (move-from-unsigned)
320 (:args (x :scs (signed-reg unsigned-reg) :target eax))
321 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)) eax)
322 (:temporary (:sc unsigned-reg :offset ebx-offset :to (:result 0) :target y)
324 (:temporary (:sc unsigned-reg :offset ecx-offset
325 :from (:argument 0) :to (:result 0)) ecx)
327 (:results (y :scs (any-reg descriptor-reg)))
328 (:note "unsigned word to integer coercion")
331 (inst call (make-fixup 'move-from-unsigned :assembly-routine))
333 ;;; Faster inline version.
334 ;;; KLUDGE: Do we really want the faster inline version? It seems awfully big..
335 ;;; If we really want speed, most likely it's only important in the non-consing
336 ;;; case, so how about about making the *ELSEWHERE* stuff into a subroutine? --
338 (define-vop (move-from-unsigned)
339 (:args (x :scs (signed-reg unsigned-reg) :to :save))
340 (:temporary (:sc unsigned-reg) alloc)
341 (:results (y :scs (any-reg descriptor-reg)))
343 (:note "unsigned word to integer coercion")
345 (aver (not (location= x y)))
346 (aver (not (location= x alloc)))
347 (aver (not (location= y alloc)))
348 (let ((bignum (gen-label))
350 (one-word-bignum (gen-label))
352 (inst test x #xe0000000)
353 (inst jmp :nz bignum)
355 (inst lea y (make-ea :dword :index x :scale 4)) ; Faster but bigger.
360 (assemble (*elsewhere*)
362 ;; Note: As on the mips port, space for a two word bignum is
363 ;; always allocated and the header size is set to either one
364 ;; or two words as appropriate.
365 (inst jmp :ns one-word-bignum)
367 (inst mov y (logior (ash (1- (+ bignum-digits-offset 2))
371 (emit-label one-word-bignum)
372 (inst mov y (logior (ash (1- (+ bignum-digits-offset 1))
377 (allocation alloc (pad-data-block (+ bignum-digits-offset 2)) node)
379 (inst lea y (make-ea :byte :base alloc :disp other-pointer-lowtag))
380 (storew x y bignum-digits-offset other-pointer-lowtag))
382 (define-move-vop move-from-unsigned :move
383 (unsigned-reg) (descriptor-reg))
385 ;;; Move untagged numbers.
386 (define-vop (word-move)
387 (:args (x :scs (signed-reg unsigned-reg) :target y
388 :load-if (not (location= x y))))
389 (:results (y :scs (signed-reg unsigned-reg)
391 (not (or (location= x y)
392 (and (sc-is x signed-reg unsigned-reg)
393 (sc-is y signed-stack unsigned-stack))))))
396 (:note "word integer move")
399 (define-move-vop word-move :move
400 (signed-reg unsigned-reg) (signed-reg unsigned-reg))
402 ;;; Move untagged number arguments/return-values.
403 (define-vop (move-word-arg)
404 (:args (x :scs (signed-reg unsigned-reg) :target y)
405 (fp :scs (any-reg) :load-if (not (sc-is y sap-reg))))
407 (:note "word integer argument move")
410 ((signed-reg unsigned-reg)
412 ((signed-stack unsigned-stack)
413 (if (= (tn-offset fp) esp-offset)
414 (storew x fp (tn-offset y)) ; c-call
415 (storew x fp (- (1+ (tn-offset y)))))))))
416 (define-move-vop move-word-arg :move-arg
417 (descriptor-reg any-reg signed-reg unsigned-reg) (signed-reg unsigned-reg))
419 ;;; Use standard MOVE-ARG and coercion to move an untagged number
420 ;;; to a descriptor passing location.
421 (define-move-vop move-arg :move-arg
422 (signed-reg unsigned-reg) (any-reg descriptor-reg))