Trivial change for consistency
[sbcl.git] / src / compiler / x86-64 / system.lisp
blob7edbf3b219feedcce3ebe5ecb9d249fe4edfcfb1
1 ;;;; x86 VM definitions of various system hacking operations
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
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.
12 (in-package "SB!VM")
14 ;;;; type frobbing VOPs
16 (define-vop (lowtag-of)
17 (:translate lowtag-of)
18 (:policy :fast-safe)
19 (:args (object :scs (any-reg descriptor-reg control-stack)
20 :target result))
21 (:results (result :scs (unsigned-reg)))
22 (:result-types positive-fixnum)
23 (:generator 1
24 (move result object)
25 (inst and result lowtag-mask)))
27 (define-vop (widetag-of)
28 (:translate widetag-of)
29 (:policy :fast-safe)
30 (:args (object :scs (descriptor-reg)))
31 (:temporary (:sc unsigned-reg :offset rax-offset :target result
32 :to (:result 0)) rax)
33 (:results (result :scs (unsigned-reg)))
34 (:result-types positive-fixnum)
35 (:generator 6
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)
43 ;; Pick off fixnums.
44 (inst test al-tn fixnum-tag-mask)
45 (inst jmp :e DONE)
47 ;; Pick off structures and list pointers.
48 (inst test al-tn 2)
49 (inst jmp :ne DONE)
51 ;; must be an other immediate
52 (inst movzx rax (reg-in-size object :byte))
53 (inst jmp DONE)
55 FUNCTION-PTR
56 (load-type rax object (- fun-pointer-lowtag))
57 (inst jmp DONE)
59 OTHER-PTR
60 (load-type rax object (- other-pointer-lowtag))
62 DONE
63 (move result rax)))
65 (define-vop (%other-pointer-widetag)
66 (:translate %other-pointer-widetag)
67 (:policy :fast-safe)
68 (:args (object :scs (descriptor-reg)))
69 (:results (result :scs (unsigned-reg)))
70 (:result-types positive-fixnum)
71 (:generator 6
72 (load-type result object (- other-pointer-lowtag))))
74 (define-vop (fun-subtype)
75 (:translate fun-subtype)
76 (:policy :fast-safe)
77 (:args (function :scs (descriptor-reg)))
78 (:results (result :scs (unsigned-reg)))
79 (:result-types positive-fixnum)
80 (:generator 6
81 (load-type result function (- fun-pointer-lowtag))))
83 (define-vop (set-fun-subtype)
84 (:translate (setf fun-subtype))
85 (:policy :fast-safe)
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)
91 eax)
92 (:results (result :scs (unsigned-reg)))
93 (:result-types positive-fixnum)
94 (:generator 6
95 (move eax type)
96 (inst mov
97 (make-ea :byte :base function :disp (- fun-pointer-lowtag))
98 al-tn)
99 (move result eax)))
101 (define-vop (get-header-data)
102 (:translate get-header-data)
103 (:policy :fast-safe)
104 (:args (x :scs (descriptor-reg)))
105 (:results (res :scs (unsigned-reg)))
106 (:result-types positive-fixnum)
107 (:generator 6
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)
113 (:policy :fast-safe)
114 (:args (x :scs (descriptor-reg)))
115 (:results (res :scs (unsigned-reg)))
116 (:result-types positive-fixnum)
117 (:generator 6
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)
123 (:policy :fast-safe)
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)
130 (:generator 6
131 (move eax data)
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)
135 (move res x)))
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)))
141 (:policy :fast-safe)
142 (:generator 1
143 (move res ptr)
144 ;; Mask the lowtag, and shift the whole address into a positive
145 ;; fixnum.
146 (inst and res (lognot lowtag-mask))
147 (inst shr res 1)))
149 ;;;; allocation
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)
155 (:policy :fast-safe)
156 (:generator 1
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)
163 (:policy :fast-safe)
164 (:generator 1
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))
176 (:policy :fast-safe)
177 (:generator 1
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)
185 (:policy :fast-safe)
186 (:generator 1
187 (move int rsp-tn)))
189 ;;;; code object frobbing
191 (define-vop (code-instructions)
192 (:translate code-instructions)
193 (:policy :fast-safe)
194 (:args (code :scs (descriptor-reg) :to (:result 0)))
195 (:results (sap :scs (sap-reg) :from (:argument 0)))
196 (:result-types system-area-pointer)
197 (:generator 10
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
201 :scale n-word-bytes
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)))
209 (:generator 10
210 (loadw func code 0 other-pointer-lowtag)
211 (inst shr func n-widetag-bits)
212 (inst lea func
213 (make-ea :byte :base offset :index func
214 :scale n-word-bytes
215 :disp (- fun-pointer-lowtag other-pointer-lowtag)))
216 (inst add func code)))
218 (define-vop (%simple-fun-self)
219 (:policy :fast-safe)
220 (:translate %simple-fun-self)
221 (:args (function :scs (descriptor-reg)))
222 (:results (result :scs (descriptor-reg)))
223 (:generator 3
224 (loadw result function simple-fun-self-slot fun-pointer-lowtag)
225 (inst lea result
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)
237 (:policy :fast-safe)
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)))
243 (:generator 3
244 (inst lea temp
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)))
251 ;;;; symbol frobbing
253 ;; only define if the feature is enabled to test building without it
254 #!+symbol-info-vops
255 (progn
256 (define-vop (symbol-info-vector)
257 (:policy :fast-safe)
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)
262 (:generator 1
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)
271 (inst cmov :e res
272 (make-ea-for-object-slot res cons-cdr-slot list-pointer-lowtag))))
273 (define-vop (symbol-plist)
274 (:policy :fast-safe)
275 (:translate symbol-plist)
276 (:args (x :scs (descriptor-reg)))
277 (:results (res :scs (descriptor-reg)))
278 (:temporary (:sc unsigned-reg) temp)
279 (:generator 1
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)
292 (:policy :fast-safe)
293 (:translate sb!unix::receive-pending-interrupt)
294 (:generator 1
295 (inst break pending-interrupt-trap)))
297 #!+sb-safepoint
298 (define-vop (insert-safepoint)
299 (:policy :fast-safe)
300 (:translate sb!kernel::gc-safepoint)
301 (:generator 0
302 (emit-safepoint)))
304 #!+sb-thread
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))
311 #!+sb-thread
312 (progn
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)
317 (:info n)
318 (:arg-types (:constant unsigned-byte))
319 (:policy :fast-safe)
320 (:generator 1
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)
328 (:policy :fast-safe)
329 (:generator 2
330 (inst mov sap
331 (make-ea :qword :base thread-base-tn :index n
332 :scale (ash 1 (- word-shift n-fixnum-tag-bits)))))))
334 (define-vop (halt)
335 (:generator 1
336 (inst break halt-trap)))
338 (defknown float-wait () (values))
339 (define-vop (float-wait)
340 (:policy :fast-safe)
341 (:translate float-wait)
342 (:vop-var vop)
343 (:save-p :compute-only)
344 (:generator 1
345 (note-next-instruction vop :internal-error)
346 (inst wait)))
348 ;;;; Miscellany
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
354 ;;; count in EDX.
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)
382 (:policy :fast-safe)
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)
388 (:ignore ebx ecx)
389 (:results (hi :scs (unsigned-reg))
390 (lo :scs (unsigned-reg)))
391 (:result-types unsigned-num unsigned-num)
392 (:generator 5
393 (zeroize eax)
394 ;; Intel docs seem quite consistent on only using CPUID before RDTSC,
395 ;; not both before and after. Go figure.
396 (inst cpuid)
397 (inst rdtsc)
398 (move lo eax)
399 (move hi edx)))
401 (defmacro with-cycle-counter (&body body)
402 #!+sb-doc
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)
410 (- ,lo1 ,lo0)))))))
412 #!+sb-dyncount
413 (define-vop (count-me)
414 (:args (count-vector :scs (descriptor-reg)))
415 (:info index)
416 (:generator 0
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)
425 (:policy :fast-safe)
426 (:translate %compiler-barrier)
427 (:generator 3))
429 #!+memory-barrier-vops
430 (define-vop (%memory-barrier)
431 (:policy :fast-safe)
432 (:translate %memory-barrier)
433 (:generator 3
434 (inst mfence)))
436 #!+memory-barrier-vops
437 (define-vop (%read-barrier)
438 (:policy :fast-safe)
439 (:translate %read-barrier)
440 (:generator 3))
442 #!+memory-barrier-vops
443 (define-vop (%write-barrier)
444 (:policy :fast-safe)
445 (:translate %write-barrier)
446 (:generator 3))
448 #!+memory-barrier-vops
449 (define-vop (%data-dependency-barrier)
450 (:policy :fast-safe)
451 (:translate %data-dependency-barrier)
452 (:generator 3))
454 (define-vop (pause)
455 (:translate spin-loop-hint)
456 (:policy :fast-safe)
457 (:generator 0
458 (inst pause)))
460 ;;;;
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.
471 (macrolet
472 ((define-cmpxchg-vop (name memory-operand more-stuff &optional index-arg)
473 `(define-vop (,name)
474 (:policy :fast)
475 ,@more-stuff
476 (:args (data :scs (descriptor-reg) :to :eval)
477 ,@index-arg
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)
492 (:generator 7
493 (move eax expected-old-lo)
494 (move edx expected-old-hi)
495 (move ebx new-lo)
496 (move ecx new-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)
537 (:policy :fast-safe)
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)
555 (:generator 5
556 (move eax function)
557 (move ecx subfunction)
558 (inst cpuid)
559 (move a eax)
560 (move b ebx)
561 (move c ecx)
562 (move d edx)))