1 ;;;; x86 VM definitions of various system hacking operations
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 ;;;; type frobbing VOPs
16 (define-vop (lowtag-of)
17 (:translate lowtag-of
)
19 (:args
(object :scs
(any-reg descriptor-reg control-stack
)
21 (:results
(result :scs
(unsigned-reg)))
22 (:result-types positive-fixnum
)
25 (inst and result lowtag-mask
)))
27 (define-vop (widetag-of)
28 (:translate widetag-of
)
30 (:args
(object :scs
(descriptor-reg)))
31 (:temporary
(:sc unsigned-reg
:offset rax-offset
:target result
33 (:results
(result :scs
(unsigned-reg)))
34 (:result-types positive-fixnum
)
36 (inst movzx rax
(reg-in-size object
:byte
))
37 (inst and al-tn lowtag-mask
)
38 (inst cmp al-tn other-pointer-lowtag
)
39 (inst jmp
:e OTHER-PTR
)
40 (inst cmp al-tn fun-pointer-lowtag
)
41 (inst jmp
:e FUNCTION-PTR
)
44 (inst test al-tn fixnum-tag-mask
)
47 ;; Pick off structures and list pointers.
51 ;; must be an other immediate
52 (inst movzx rax
(reg-in-size object
:byte
))
56 (load-type rax object
(- fun-pointer-lowtag
))
60 (load-type rax object
(- other-pointer-lowtag
))
65 (define-vop (%other-pointer-widetag
)
66 (:translate %other-pointer-widetag
)
68 (:args
(object :scs
(descriptor-reg)))
69 (:results
(result :scs
(unsigned-reg)))
70 (:result-types positive-fixnum
)
72 (load-type result object
(- other-pointer-lowtag
))))
74 (define-vop (fun-subtype)
75 (:translate fun-subtype
)
77 (:args
(function :scs
(descriptor-reg)))
78 (:results
(result :scs
(unsigned-reg)))
79 (:result-types positive-fixnum
)
81 (load-type result function
(- fun-pointer-lowtag
))))
83 (define-vop (set-fun-subtype)
84 (:translate
(setf fun-subtype
))
86 (:args
(type :scs
(unsigned-reg) :target eax
)
87 (function :scs
(descriptor-reg)))
88 (:arg-types positive-fixnum
*)
89 (:temporary
(:sc unsigned-reg
:offset rax-offset
:from
(:argument
0)
90 :to
(:result
0) :target result
)
92 (:results
(result :scs
(unsigned-reg)))
93 (:result-types positive-fixnum
)
97 (make-ea :byte
:base function
:disp
(- fun-pointer-lowtag
))
101 (define-vop (get-header-data)
102 (:translate get-header-data
)
104 (:args
(x :scs
(descriptor-reg)))
105 (:results
(res :scs
(unsigned-reg)))
106 (:result-types positive-fixnum
)
108 (loadw res x
0 other-pointer-lowtag
)
109 (inst shr res n-widetag-bits
)))
111 (define-vop (get-closure-length)
112 (:translate get-closure-length
)
114 (:args
(x :scs
(descriptor-reg)))
115 (:results
(res :scs
(unsigned-reg)))
116 (:result-types positive-fixnum
)
118 (loadw res x
0 fun-pointer-lowtag
)
119 (inst shr res n-widetag-bits
)))
121 (define-vop (set-header-data)
122 (:translate set-header-data
)
124 (:args
(x :scs
(descriptor-reg) :target res
:to
(:result
0))
125 (data :scs
(any-reg) :target eax
))
126 (:arg-types
* positive-fixnum
)
127 (:results
(res :scs
(descriptor-reg)))
128 (:temporary
(:sc unsigned-reg
:offset eax-offset
129 :from
(:argument
1) :to
(:result
0)) eax
)
132 (inst shl eax
(- n-widetag-bits n-fixnum-tag-bits
))
133 (inst mov al-tn
(make-ea :byte
:base x
:disp
(- other-pointer-lowtag
)))
134 (storew eax x
0 other-pointer-lowtag
)
137 (define-vop (pointer-hash)
138 (:translate pointer-hash
)
139 (:args
(ptr :scs
(any-reg descriptor-reg
) :target res
))
140 (:results
(res :scs
(any-reg descriptor-reg
)))
144 ;; Mask the lowtag, and shift the whole address into a positive
146 (inst and res
(lognot lowtag-mask
))
151 (define-vop (dynamic-space-free-pointer)
152 (:results
(int :scs
(sap-reg)))
153 (:result-types system-area-pointer
)
154 (:translate dynamic-space-free-pointer
)
157 (load-symbol-value int
*allocation-pointer
*)))
159 (define-vop (binding-stack-pointer-sap)
160 (:results
(int :scs
(sap-reg)))
161 (:result-types system-area-pointer
)
162 (:translate binding-stack-pointer-sap
)
165 (load-binding-stack-pointer int
)))
167 (defknown (setf binding-stack-pointer-sap
)
168 (system-area-pointer) system-area-pointer
())
170 (define-vop (set-binding-stack-pointer-sap)
171 (:args
(new-value :scs
(sap-reg) :target int
))
172 (:arg-types system-area-pointer
)
173 (:results
(int :scs
(sap-reg)))
174 (:result-types system-area-pointer
)
175 (:translate
(setf binding-stack-pointer-sap
))
178 (store-binding-stack-pointer new-value
)
179 (move int new-value
)))
181 (define-vop (control-stack-pointer-sap)
182 (:results
(int :scs
(sap-reg)))
183 (:result-types system-area-pointer
)
184 (:translate control-stack-pointer-sap
)
189 ;;;; code object frobbing
191 (define-vop (code-instructions)
192 (:translate code-instructions
)
194 (:args
(code :scs
(descriptor-reg) :to
(:result
0)))
195 (:results
(sap :scs
(sap-reg) :from
(:argument
0)))
196 (:result-types system-area-pointer
)
198 (loadw sap code
0 other-pointer-lowtag
)
199 (inst shr sap n-widetag-bits
)
200 (inst lea sap
(make-ea :byte
:base code
:index sap
202 :disp
(- other-pointer-lowtag
)))))
204 (define-vop (compute-fun)
205 (:args
(code :scs
(descriptor-reg) :to
(:result
0))
206 (offset :scs
(signed-reg unsigned-reg
) :to
(:result
0)))
207 (:arg-types
* positive-fixnum
)
208 (:results
(func :scs
(descriptor-reg) :from
(:argument
0)))
210 (loadw func code
0 other-pointer-lowtag
)
211 (inst shr func n-widetag-bits
)
213 (make-ea :byte
:base offset
:index func
215 :disp
(- fun-pointer-lowtag other-pointer-lowtag
)))
216 (inst add func code
)))
218 (define-vop (%simple-fun-self
)
220 (:translate %simple-fun-self
)
221 (:args
(function :scs
(descriptor-reg)))
222 (:results
(result :scs
(descriptor-reg)))
224 (loadw result function simple-fun-self-slot fun-pointer-lowtag
)
226 (make-ea :byte
:base result
227 :disp
(- fun-pointer-lowtag
228 (* simple-fun-code-offset n-word-bytes
))))))
230 ;;; The closure function slot is a pointer to raw code on X86 instead
231 ;;; of a pointer to the code function object itself. This VOP is used
232 ;;; to reference the function object given the closure object.
233 (define-source-transform %closure-fun
(closure)
234 `(%simple-fun-self
,closure
))
236 (define-vop (%set-fun-self
)
238 (:translate
(setf %simple-fun-self
))
239 (:args
(new-self :scs
(descriptor-reg) :target result
:to
:result
)
240 (function :scs
(descriptor-reg) :to
:result
))
241 (:temporary
(:sc any-reg
:from
(:argument
0) :to
:result
) temp
)
242 (:results
(result :scs
(descriptor-reg)))
245 (make-ea :byte
:base new-self
246 :disp
(- (ash simple-fun-code-offset word-shift
)
247 fun-pointer-lowtag
)))
248 (storew temp function simple-fun-self-slot fun-pointer-lowtag
)
249 (move result new-self
)))
253 ;; only define if the feature is enabled to test building without it
256 (define-vop (symbol-info-vector)
258 (:translate symbol-info-vector
)
259 (:args
(x :scs
(descriptor-reg)))
260 (:results
(res :scs
(descriptor-reg)))
261 (:temporary
(:sc unsigned-reg
:offset rax-offset
) rax
)
263 (loadw res x symbol-info-slot other-pointer-lowtag
)
264 ;; If RES has list-pointer-lowtag, take its CDR. If not, use it as-is.
265 ;; This CMOV safely reads from memory when it does not move, because if
266 ;; there is an info-vector in the slot, it has at least one element.
267 ;; This would compile to almost the same code without a VOP,
268 ;; but using a jmp around a mov instead.
269 (inst lea rax
(make-ea :dword
:base res
:disp
(- list-pointer-lowtag
)))
270 (inst test
(reg-in-size rax
:byte
) lowtag-mask
)
272 (make-ea-for-object-slot res cons-cdr-slot list-pointer-lowtag
))))
273 (define-vop (symbol-plist)
275 (:translate symbol-plist
)
276 (:args
(x :scs
(descriptor-reg)))
277 (:results
(res :scs
(descriptor-reg)))
278 (:temporary
(:sc unsigned-reg
) temp
)
280 (loadw res x symbol-info-slot other-pointer-lowtag
)
281 ;; Instruction pun: (CAR x) is the same as (VECTOR-LENGTH x)
282 ;; so if the info slot holds a vector, this gets a fixnum- it's not a plist.
283 (loadw res res cons-car-slot list-pointer-lowtag
)
284 (inst mov temp nil-value
)
285 (inst test
(reg-in-size res
:byte
) fixnum-tag-mask
)
286 (inst cmov
:e res temp
))))
288 ;;;; other miscellaneous VOPs
290 (defknown sb
!unix
::receive-pending-interrupt
() (values))
291 (define-vop (sb!unix
::receive-pending-interrupt
)
293 (:translate sb
!unix
::receive-pending-interrupt
)
295 (inst break pending-interrupt-trap
)))
298 (define-vop (insert-safepoint)
300 (:translate sb
!kernel
::gc-safepoint
)
305 ;; 28 unsigned bits is the max before shifting left by 3 that fits in the
306 ;; 'displacement' of an EA. This is hugely generous. The largest offset
307 ;; you'd ever supply is THREAD-NONPOINTER-DATA-SLOT + interrupt depth.
308 (defknown current-thread-offset-sap
((unsigned-byte 28))
309 system-area-pointer
(flushable))
313 (define-vop (current-thread-offset-sap/c
)
314 (:results
(sap :scs
(sap-reg)))
315 (:result-types system-area-pointer
)
316 (:translate current-thread-offset-sap
)
318 (:arg-types
(:constant unsigned-byte
))
321 (inst mov sap
(make-ea :qword
:base thread-base-tn
:disp
(ash n
3)))))
322 (define-vop (current-thread-offset-sap)
323 (:results
(sap :scs
(sap-reg)))
324 (:result-types system-area-pointer
)
325 (:translate current-thread-offset-sap
)
326 (:args
(n :scs
(any-reg) :target sap
))
327 (:arg-types tagged-num
)
331 (make-ea :qword
:base thread-base-tn
:index n
332 :scale
(ash 1 (- 3 n-fixnum-tag-bits
)))))))
336 (inst break halt-trap
)))
338 (defknown float-wait
() (values))
339 (define-vop (float-wait)
341 (:translate float-wait
)
343 (:save-p
:compute-only
)
345 (note-next-instruction vop
:internal-error
)
350 ;;; the RDTSC instruction (present on Pentium processors and
351 ;;; successors) allows you to access the time-stamp counter, a 64-bit
352 ;;; model-specific register that counts executed cycles. The
353 ;;; instruction returns the low cycle count in EAX and high cycle
356 ;;; In order to obtain more significant results on out-of-order
357 ;;; processors (such as the Pentium II and later), we issue a
358 ;;; serializing CPUID instruction before and after reading the cycle
359 ;;; counter. This instruction is used for its side effect of emptying
360 ;;; the processor pipeline, to ensure that the RDTSC instruction is
361 ;;; executed once all pending instructions have been completed and
362 ;;; before any others. CPUID writes to EBX and ECX in addition to EAX
363 ;;; and EDX, so they need to be added as temporaries.
365 ;;; Note that cache effects mean that the cycle count can vary for
366 ;;; different executions of the same code (it counts cycles, not
367 ;;; retired instructions). Furthermore, the results are per-processor
368 ;;; and not per-process, so are unreliable on multiprocessor machines
369 ;;; where processes can migrate between processors.
371 ;;; This method of obtaining a cycle count has the advantage of being
372 ;;; very fast (around 20 cycles), and of not requiring a system call.
373 ;;; However, you need to know your processor's clock speed to translate
374 ;;; this into real execution time.
376 ;;; FIXME: This about the WITH-CYCLE-COUNTER interface a bit, and then
377 ;;; perhaps export it from SB-SYS.
379 (defknown %read-cycle-counter
() (values (unsigned-byte 32) (unsigned-byte 32)) ())
381 (define-vop (%read-cycle-counter
)
383 (:translate %read-cycle-counter
)
384 (:temporary
(:sc unsigned-reg
:offset eax-offset
:target lo
) eax
)
385 (:temporary
(:sc unsigned-reg
:offset edx-offset
:target hi
) edx
)
386 (:temporary
(:sc unsigned-reg
:offset ebx-offset
) ebx
)
387 (:temporary
(:sc unsigned-reg
:offset ecx-offset
) ecx
)
389 (:results
(hi :scs
(unsigned-reg))
390 (lo :scs
(unsigned-reg)))
391 (:result-types unsigned-num unsigned-num
)
394 ;; Intel docs seem quite consistent on only using CPUID before RDTSC,
395 ;; not both before and after. Go figure.
401 (defmacro with-cycle-counter
(&body body
)
403 "Returns the primary value of BODY as the primary value, and the
404 number of CPU cycles elapsed as secondary value. EXPERIMENTAL."
405 (with-unique-names (hi0 hi1 lo0 lo1
)
406 `(multiple-value-bind (,hi0
,lo0
) (%read-cycle-counter
)
407 (values (locally ,@body
)
408 (multiple-value-bind (,hi1
,lo1
) (%read-cycle-counter
)
409 (+ (ash (- ,hi1
,hi0
) 32)
413 (define-vop (count-me)
414 (:args
(count-vector :scs
(descriptor-reg)))
417 (inst inc
(make-ea :qword
:base count-vector
418 :disp
(- (* (+ vector-data-offset index
) n-word-bytes
)
419 other-pointer-lowtag
)))))
421 ;;;; Memory barrier support
423 #!+memory-barrier-vops
424 (define-vop (%compiler-barrier
)
426 (:translate %compiler-barrier
)
429 #!+memory-barrier-vops
430 (define-vop (%memory-barrier
)
432 (:translate %memory-barrier
)
436 #!+memory-barrier-vops
437 (define-vop (%read-barrier
)
439 (:translate %read-barrier
)
442 #!+memory-barrier-vops
443 (define-vop (%write-barrier
)
445 (:translate %write-barrier
)
448 #!+memory-barrier-vops
449 (define-vop (%data-dependency-barrier
)
451 (:translate %data-dependency-barrier
)
455 (:translate spin-loop-hint
)
462 (defknown %cons-cas-pair
(cons t t t t
) (values t t
))
463 ;; These unsafely permits cmpxchg on any kind of vector, boxed or unboxed
464 ;; and the same goes for instances.
465 (defknown %vector-cas-pair
(simple-array index t t t t
) (values t t
))
466 (defknown %instance-cas-pair
(instance index t t t t
) (values t t
))
468 ;; 32-bit register names here are not an accident - it's a deliberate attempt
469 ;; to keep this exactly in sync with 32-bit code in the hope that somebody
470 ;; will invent a way to share things in common.
472 ((define-cmpxchg-vop (name memory-operand more-stuff
&optional index-arg
)
476 (:args
(data :scs
(descriptor-reg) :to
:eval
)
478 (expected-old-lo :scs
(descriptor-reg any-reg
) :target eax
)
479 (expected-old-hi :scs
(descriptor-reg any-reg
) :target edx
)
480 (new-lo :scs
(descriptor-reg any-reg
) :target ebx
)
481 (new-hi :scs
(descriptor-reg any-reg
) :target ecx
))
482 (:results
(result-lo :scs
(descriptor-reg any-reg
))
483 (result-hi :scs
(descriptor-reg any-reg
)))
484 (:temporary
(:sc unsigned-reg
:offset eax-offset
485 :from
(:argument
2) :to
(:result
0)) eax
)
486 (:temporary
(:sc unsigned-reg
:offset edx-offset
487 :from
(:argument
3) :to
(:result
0)) edx
)
488 (:temporary
(:sc unsigned-reg
:offset ebx-offset
489 :from
(:argument
4) :to
(:result
0)) ebx
)
490 (:temporary
(:sc unsigned-reg
:offset ecx-offset
491 :from
(:argument
5) :to
(:result
0)) ecx
)
493 (move eax expected-old-lo
)
494 (move edx expected-old-hi
)
497 (inst cmpxchg16b
,memory-operand
:lock
)
498 ;; EDX:EAX hold the actual old contents of memory.
499 ;; Manually analyze result lifetimes to avoid clobbering.
500 (cond ((and (location= result-lo edx
) (location= result-hi eax
))
501 (inst xchg eax edx
)) ; unlikely, but possible
502 ((location= result-lo edx
) ; result-hi is not eax
503 (move result-hi edx
) ; move high part first
504 (move result-lo eax
))
505 (t ; result-lo is not edx
506 (move result-lo eax
) ; move low part first
507 (move result-hi edx
)))))))
508 (define-cmpxchg-vop compare-and-exchange-pair
509 (make-ea :dword
:base data
:disp
(- list-pointer-lowtag
))
510 ((:translate %cons-cas-pair
)))
511 (define-cmpxchg-vop compare-and-exchange-pair-indexed
512 (make-ea :dword
:base data
:disp offset
:index index
513 :scale
(ash n-word-bytes
(- n-fixnum-tag-bits
)))
514 ((:variant-vars offset
))
515 ((index :scs
(descriptor-reg any-reg
) :to
:eval
))))
517 ;; The CPU requires 16-byte alignment for the memory operand.
518 ;; A vector's data portion starts on a 16-byte boundary,
519 ;; so any even numbered index is OK.
520 (define-vop (%vector-cas-pair compare-and-exchange-pair-indexed
)
521 (:translate %vector-cas-pair
)
522 (:variant
(- (* n-word-bytes vector-data-offset
) other-pointer-lowtag
)))
524 ;; Here you specify an odd numbered slot, otherwise get a bus error.
525 ;; An instance's first user-visible slot at index 1 is 16-byte-aligned.
526 (define-vop (%instance-cas-pair compare-and-exchange-pair-indexed
)
527 (:translate %instance-cas-pair
)
528 (:variant
(- (* n-word-bytes instance-slots-offset
) instance-pointer-lowtag
)))
530 (defknown %cpu-identification
((unsigned-byte 32) (unsigned-byte 32))
531 (values (unsigned-byte 32) (unsigned-byte 32)
532 (unsigned-byte 32) (unsigned-byte 32)))
534 ;; This instruction does in fact not utilize all bits of the full width (Rxx)
535 ;; regs so it would be wonderful to share this verbatim with x86 32-bit.
536 (define-vop (%cpu-identification
)
538 (:translate %cpu-identification
)
539 (:args
(function :scs
(unsigned-reg) :target eax
)
540 (subfunction :scs
(unsigned-reg) :target ecx
))
541 (:arg-types unsigned-num unsigned-num
)
542 (:results
(a :scs
(unsigned-reg))
543 (b :scs
(unsigned-reg))
544 (c :scs
(unsigned-reg))
545 (d :scs
(unsigned-reg)))
546 (:result-types unsigned-num unsigned-num unsigned-num unsigned-num
)
547 (:temporary
(:sc unsigned-reg
:from
(:argument
0) :to
(:result
0)
548 :offset eax-offset
) eax
)
549 (:temporary
(:sc unsigned-reg
:from
(:argument
1) :to
(:result
2)
550 :offset ecx-offset
) ecx
)
551 (:temporary
(:sc unsigned-reg
:from
:eval
:to
(:result
3)
552 :offset edx-offset
) edx
)
553 (:temporary
(:sc unsigned-reg
:from
:eval
:to
(:result
1)
554 :offset ebx-offset
) ebx
)
557 (move ecx subfunction
)