Fix typo (missing closing paren).
[projects/cmucl/cmucl.git] / src / compiler / x86 / system.lisp
CommitLineData
3832e020 14;;; -*- Mode: LISP; Syntax: Common-Lisp; Base: 10; Package: x86 -*-
c0c98ded 2;;;
3;;; **********************************************************************
4;;; This code was written as part of the CMU Common Lisp project at
5;;; Carnegie Mellon University, and has been placed in the public domain.
6;;; If you want to use this code or any part of CMU Common Lisp, please contact
7;;; Scott Fahlman or slisp-group@cs.cmu.edu.
8;;;
9(ext:file-comment
99a5797f 10 "$Header: src/compiler/x86/system.lisp $")
c0c98ded 11;;;
12;;; **********************************************************************
13;;;
14;;; x86 VM definitions of various system hacking operations.
15;;;
16;;; Written by William Lott.
17;;;
18;;; Debugged by Paul F. Werkowski Spring/Summer 1995.
e420c35c 19;;; Enhancements/debugging by Douglas T. Crosher 1996,1997,1998,1999.
c0c98ded 20;;;
21
22(in-package :x86)
bc22f7b9 23(intl:textdomain "cmucl-x86-vm")
c0c98ded 24
25\f
26;;;; Type frobbing VOPs
27
28(define-vop (get-lowtag)
29 (:translate get-lowtag)
30 (:policy :fast-safe)
9bf4134d 31 (:args (object :scs (any-reg descriptor-reg control-stack)
c0c98ded 32 :target result))
33 (:results (result :scs (unsigned-reg)))
34 (:result-types positive-fixnum)
35 (:generator 1
36 (move result object)
37 (inst and result lowtag-mask)))
38
39(define-vop (get-type)
40 (:translate get-type)
41 (:policy :fast-safe)
42 (:args (object :scs (descriptor-reg)))
f19779c5 43 (:temporary (:sc unsigned-reg :offset eax-offset :to (:result 0)) eax)
c0c98ded 44 (:results (result :scs (unsigned-reg)))
45 (:result-types positive-fixnum)
46 (:generator 6
47 (inst mov eax object)
48 (inst and al-tn lowtag-mask)
49 (inst cmp al-tn other-pointer-type)
50 (inst jmp :e other-ptr)
51 (inst cmp al-tn function-pointer-type)
52 (inst jmp :e function-ptr)
53
54 ;; pick off structures and list pointers
55 (inst test al-tn 1)
56 (inst jmp :ne done)
57
58 ;; pick off fixnums
59 (inst and al-tn 3)
60 (inst jmp :e done)
61
62 ;; must be an other immediate
63 (inst mov eax object)
64 (inst jmp done)
65
66 FUNCTION-PTR
67 (load-type al-tn object (- vm:function-pointer-type))
68 (inst jmp done)
69
70 OTHER-PTR
71 (load-type al-tn object (- vm:other-pointer-type))
72
73 DONE
74 (inst movzx result al-tn)))
75\f
76(define-vop (function-subtype)
77 (:translate function-subtype)
78 (:policy :fast-safe)
79 (:args (function :scs (descriptor-reg)))
80 (:temporary (:sc byte-reg :from (:eval 0) :to (:eval 1)) temp)
81 (:results (result :scs (unsigned-reg)))
82 (:result-types positive-fixnum)
83 (:generator 6
84 (load-type temp function (- vm:function-pointer-type))
85 (inst movzx result temp)))
86
87(define-vop (set-function-subtype)
88 (:translate (setf function-subtype))
89 (:policy :fast-safe)
90 (:args (type :scs (unsigned-reg) :target eax)
91 (function :scs (descriptor-reg)))
92 (:arg-types positive-fixnum *)
f19779c5 93 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)
c0c98ded 94 :to (:result 0) :target result)
95 eax)
96 (:results (result :scs (unsigned-reg)))
97 (:result-types positive-fixnum)
98 (:generator 6
99 (move eax type)
100 (inst mov
101 (make-ea :byte :base function :disp (- function-pointer-type))
102 al-tn)
103 (move result eax)))
104
105(define-vop (get-header-data)
106 (:translate get-header-data)
107 (:policy :fast-safe)
108 (:args (x :scs (descriptor-reg)))
109 (:results (res :scs (unsigned-reg)))
110 (:result-types positive-fixnum)
111 (:generator 6
112 (loadw res x 0 other-pointer-type)
113 (inst shr res type-bits)))
114
115(define-vop (get-closure-length)
116 (:translate get-closure-length)
117 (:policy :fast-safe)
118 (:args (x :scs (descriptor-reg)))
119 (:results (res :scs (unsigned-reg)))
120 (:result-types positive-fixnum)
121 (:generator 6
122 (loadw res x 0 function-pointer-type)
123 (inst shr res type-bits)))
124
125(define-vop (set-header-data)
126 (:translate set-header-data)
127 (:policy :fast-safe)
128 (:args (x :scs (descriptor-reg) :target res :to (:result 0))
129 (data :scs (any-reg) :target eax))
130 (:arg-types * positive-fixnum)
131 (:results (res :scs (descriptor-reg)))
f19779c5 132 (:temporary (:sc unsigned-reg :offset eax-offset
c0c98ded 133 :from (:argument 1) :to (:result 0)) eax)
134 (:generator 6
135 (move eax data)
136 (inst shl eax (- type-bits 2))
137 (inst mov al-tn (make-ea :byte :base x :disp (- other-pointer-type)))
138 (storew eax x 0 other-pointer-type)
139 (move res x)))
140\f
141(define-vop (make-fixnum)
142 (:args (ptr :scs (any-reg descriptor-reg) :target res))
143 (:results (res :scs (any-reg descriptor-reg)))
144 (:generator 1
145 ;;
146 ;; Some code (the hash table code) depends on this returning a
147 ;; positive number so make sure it does.
148 (move res ptr)
149 (inst shl res 3)
150 (inst shr res 1)))
151
152(define-vop (make-other-immediate-type)
153 (:args (val :scs (any-reg descriptor-reg) :target res)
154 (type :scs (unsigned-reg immediate)))
155 (:results (res :scs (any-reg descriptor-reg) :from (:argument 0)))
156 (:generator 2
157 (move res val)
158 (inst shl res (- type-bits 2))
159 (inst or res (sc-case type
160 (unsigned-reg type)
161 (immediate (tn-value type))))))
162
163\f
164;;;; Allocation
165
166(define-vop (dynamic-space-free-pointer)
167 (:results (int :scs (sap-reg)))
168 (:result-types system-area-pointer)
169 (:translate dynamic-space-free-pointer)
170 (:policy :fast-safe)
171 (:generator 1
5d85169b 172 (load-symbol-value int *allocation-pointer*)))
c0c98ded 173
174(define-vop (binding-stack-pointer-sap)
175 (:results (int :scs (sap-reg)))
176 (:result-types system-area-pointer)
177 (:translate binding-stack-pointer-sap)
178 (:policy :fast-safe)
179 (:generator 1
5d85169b 180 (load-symbol-value int *binding-stack-pointer*)))
c0c98ded 181
5256503f 182(defknown (setf binding-stack-pointer-sap)
183 (system-area-pointer) system-area-pointer ())
184
185(define-vop (set-binding-stack-pointer-sap)
186 (:args (new-value :scs (sap-reg) :target int))
187 (:arg-types system-area-pointer)
188 (:results (int :scs (sap-reg)))
189 (:result-types system-area-pointer)
190 (:translate (setf binding-stack-pointer-sap))
191 (:policy :fast-safe)
192 (:generator 1
193 (store-symbol-value new-value *binding-stack-pointer*)
194 (move int new-value)))
195
c0c98ded 196(define-vop (control-stack-pointer-sap)
197 (:results (int :scs (sap-reg)))
198 (:result-types system-area-pointer)
199 (:translate control-stack-pointer-sap)
200 (:policy :fast-safe)
201 (:generator 1
202 (move int esp-tn)))
203
204\f
205;;;; Code object frobbing.
206
207(define-vop (code-instructions)
208 (:translate code-instructions)
209 (:policy :fast-safe)
210 (:args (code :scs (descriptor-reg) :to (:result 0)))
211 (:results (sap :scs (sap-reg) :from (:argument 0)))
212 (:result-types system-area-pointer)
213 (:generator 10
214 (loadw sap code 0 other-pointer-type)
215 (inst shr sap type-bits)
216 (inst lea sap (make-ea :byte :base code :index sap :scale 4
217 :disp (- other-pointer-type)))))
218
219(define-vop (compute-function)
220 (:args (code :scs (descriptor-reg) :to (:result 0))
221 (offset :scs (signed-reg unsigned-reg) :to (:result 0)))
222 (:arg-types * positive-fixnum)
223 (:results (func :scs (descriptor-reg) :from (:argument 0)))
224 (:generator 10
225 (loadw func code 0 other-pointer-type)
226 (inst shr func type-bits)
227 (inst lea func
228 (make-ea :byte :base offset :index func :scale 4
229 :disp (- function-pointer-type other-pointer-type)))
230 (inst add func code)))
231
232(defknown %function-self (function) function (flushable))
233
234(define-vop (%function-self)
235 (:policy :fast-safe)
236 (:translate %function-self)
237 (:args (function :scs (descriptor-reg)))
238 (:results (result :scs (descriptor-reg)))
239 (:generator 3
240 (loadw result function function-self-slot function-pointer-type)
241 (inst lea result
242 (make-ea :byte :base result
243 :disp (- function-pointer-type
244 (* function-code-offset word-bytes))))))
245
246;;; Closure function slot is a pointer to raw code on X86 instead of
247;;; a pointer to the code function object itself. This VOP is used
248;;; to reference the function object given the closure object.
249(def-source-transform %closure-function (closure)
250 `(%function-self ,closure))
251
252(def-source-transform %funcallable-instance-function (fin)
253 `(%function-self ,fin))
254
255(defknown (setf %function-self) (function function) function (unsafe))
256
257(define-vop (%set-function-self)
258 (:policy :fast-safe)
259 (:translate (setf %function-self))
260 (:args (new-self :scs (descriptor-reg) :target result :to :result)
261 (function :scs (descriptor-reg) :to :result))
262 (:temporary (:sc any-reg :from (:argument 0) :to :result) temp)
263 (:results (result :scs (descriptor-reg)))
264 (:generator 3
265 (inst lea temp
266 (make-ea :byte :base new-self
267 :disp (- (ash function-code-offset word-shift)
268 function-pointer-type)))
269 (storew temp function function-self-slot function-pointer-type)
270 (move result new-self)))
271
272;; Would have really liked to use a source-transform for this, but they
273;; don't work with setf functions.
274;;
275(defknown ((setf %funcallable-instance-function)) (function function) function
276 (unsafe))
277(deftransform (setf %funcallable-instance-function) ((value fin))
278 '(setf (%function-self fin) value))
279
280
281\f
282;;;; Other random VOPs.
283
284(defknown unix::do-pending-interrupt () (values))
285(define-vop (unix::do-pending-interrupt)
286 (:policy :fast-safe)
287 (:translate unix::do-pending-interrupt)
288 (:generator 1
fe5a09fc 289 (inst break pending-interrupt-trap)))
c0c98ded 290
291(define-vop (halt)
292 (:generator 1
fe5a09fc 293 (inst break halt-trap)))
c0c98ded 294
c0c98ded 295(defknown float-wait () (values))
296(define-vop (float-wait)
297 (:policy :fast-safe)
298 (:translate float-wait)
299 (:vop-var vop)
300 (:save-p :compute-only)
301 (:generator 1
302 (note-next-instruction vop :internal-error)
303 (inst wait)))
304\f
305;;;; Dynamic vop count collection support
306
307(define-vop (count-me)
308 (:args (count-vector :scs (descriptor-reg)))
309 (:info index)
310 (:generator 0
311 (inst inc (make-ea :dword :base count-vector
312 :disp (- (* (+ vector-data-offset index) word-bytes)
313 other-pointer-type)))))
5256503f 314
315\f
e420c35c 316
670d643f 317(defknown lisp::%scrub-control-stack () (values))
e420c35c 318
319;;; Scrub the control stack.
320;;;
321;;; On the x86 port the stack grows downwards, and to support grow on
322;;; demand stacks the stack must be decreased as it is scrubbed.
323;;;
670d643f 324(define-vop (%scrub-control-stack)
e420c35c 325 (:policy :fast-safe)
670d643f 326 (:translate lisp::%scrub-control-stack)
e420c35c 327 (:args)
328 (:results)
329 (:temporary (:sc unsigned-reg) count)
330 (:temporary (:sc any-reg) stack-save zero)
331 (:generator 25
332 (inst mov stack-save esp-tn)
333 (inst mov zero 0)
334 (inst push zero)
335 ;; Scrub the stack.
336 SCRUB
337 (inst add esp-tn 4)
338 (inst mov count 2048)
339 SCRUB-LOOP
340 (inst dec count)
341 (inst push zero)
342 (inst jmp :nz SCRUB-LOOP)
343 ;; Look for a clear stack unit.
344 (inst mov count 2048)
345 LOOK-LOOP
346 (inst sub esp-tn 4)
347 (inst cmp (make-ea :dword :base esp-tn) zero)
348 (inst jmp :ne SCRUB)
349 (inst dec count)
350 (inst jmp :nz LOOK-LOOP)
351 ;; Done, restore the stack pointer.
352 (inst mov esp-tn stack-save)))
353
354\f
5256503f 355;;;; Primitive multi-thread support.
356
357(export 'control-stack-fork)
2959142b 358(defknown control-stack-fork ((simple-array (unsigned-byte 32) (*)) t)
5256503f 359 (member t nil))
360
361(define-vop (control-stack-fork)
362 (:policy :fast-safe)
363 (:translate control-stack-fork)
2959142b 364 (:args (save-stack :scs (descriptor-reg) :to :result)
365 (inherit :scs (descriptor-reg)))
366 (:arg-types simple-array-unsigned-byte-32 *)
5256503f 367 (:results (child :scs (descriptor-reg)))
368 (:result-types t)
369 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) index)
370 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) stack)
371 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) temp)
372 (:save-p t)
373 (:generator 25
2959142b 374 (inst cmp inherit nil-value)
375 (inst jmp :e FRESH-STACK)
376
377 ;; Child inherits the stack of the parent.
378
5256503f 379 ;; Setup the return context.
2959142b 380 (inst push (make-fixup nil :code-object return))
5256503f 381 (inst push ebp-tn)
382 ;; Save the stack.
383 (inst xor index index)
384 ;; First the stack-pointer.
385 (inst mov (make-ea :dword :base save-stack :index index :scale 4
386 :disp (- (* vm:vector-data-offset vm:word-bytes)
387 vm:other-pointer-type))
388 esp-tn)
389 (inst inc index)
bf84be07 390 (load-foreign-data-symbol stack "control_stack_end")
391 (inst mov stack (make-ea :dword :base stack))
2959142b 392 (inst jmp-short LOOP)
393
394 FRESH-STACK
395 ;; Child has a fresh control stack.
396
397 ;; Setup the return context.
398 (inst push (make-fixup nil :code-object return))
bf84be07 399 (load-foreign-data-symbol stack "control_stack_end")
400 (inst mov stack (make-ea :dword :base stack))
2959142b 401 ;; New FP is the Top of the stack.
402 (inst push stack)
403 ;; Save the stack.
404 (inst xor index index)
405 ;; First save the adjusted stack-pointer.
406 (inst sub stack ebp-tn)
407 (inst add stack esp-tn)
408 (inst mov (make-ea :dword :base save-stack :index index :scale 4
409 :disp (- (* vm:vector-data-offset vm:word-bytes)
410 vm:other-pointer-type))
411 stack)
412 ;; Save the current frame, replacing the OCFP and RA by 0.
413 (inst mov (make-ea :dword :base save-stack :index index :scale 4
414 :disp (- (* (+ vm:vector-data-offset 1) vm:word-bytes)
415 vm:other-pointer-type))
416 0)
417 ;; Save 0 for the OCFP.
418 (inst mov (make-ea :dword :base save-stack :index index :scale 4
419 :disp (- (* (+ vm:vector-data-offset 2) vm:word-bytes)
420 vm:other-pointer-type))
421 0)
422 (inst add index 3)
423 ;; Copy the remainder of the frame, skiping the OCFP and RA which
424 ;; are saved above.
425 (inst lea stack (make-ea :byte :base ebp-tn :disp -8))
426
5256503f 427 LOOP
428 (inst cmp stack esp-tn)
2959142b 429 (inst jmp :le stack-save-done)
5256503f 430 (inst sub stack 4)
431 (inst mov temp (make-ea :dword :base stack))
432 (inst mov (make-ea :dword :base save-stack :index index :scale 4
433 :disp (- (* vm:vector-data-offset vm:word-bytes)
434 vm:other-pointer-type))
435 temp)
436 (inst inc index)
437 (inst jmp-short LOOP)
438
439 RETURN
440 ;; Stack already clean if it reaches here. Parent returns NIL.
441 (inst mov child nil-value)
442 (inst jmp-short DONE)
443
444 STACK-SAVE-DONE
445 ;; Cleanup the stack
446 (inst add esp-tn 8)
447 ;; Child returns T.
448 (load-symbol child t)
449 DONE))
450
451(export 'control-stack-resume)
452(defknown control-stack-resume ((simple-array (unsigned-byte 32) (*))
453 (simple-array (unsigned-byte 32) (*)))
454 (values))
455
456(define-vop (control-stack-resume)
457 (:policy :fast-safe)
458 (:translate control-stack-resume)
459 (:args (save-stack :scs (descriptor-reg) :to :result)
460 (new-stack :scs (descriptor-reg) :to :result))
461 (:arg-types simple-array-unsigned-byte-32 simple-array-unsigned-byte-32)
462 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) index)
463 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) stack)
464 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) temp)
465 (:save-p t)
466 (:generator 25
467 ;; Setup the return context.
468 (inst push (make-fixup nil :code-object RETURN))
469 (inst push ebp-tn)
470 ;; Save the stack.
471 (inst xor index index)
472 ;; First the stack-pointer.
473 (inst mov (make-ea :dword :base save-stack :index index :scale 4
474 :disp (- (* vm:vector-data-offset vm:word-bytes)
475 vm:other-pointer-type))
476 esp-tn)
477 (inst inc index)
bf84be07 478 (load-foreign-data-symbol stack "control_stack_end")
479 (inst mov stack (make-ea :dword :base stack))
5256503f 480 LOOP
481 (inst cmp stack esp-tn)
482 (inst jmp :le STACK-SAVE-DONE)
483 (inst sub stack 4)
484 (inst mov temp (make-ea :dword :base stack))
485 (inst mov (make-ea :dword :base save-stack :index index :scale 4
486 :disp (- (* vm:vector-data-offset vm:word-bytes)
487 vm:other-pointer-type))
488 temp)
489 (inst inc index)
490 (inst jmp-short LOOP)
491
492 STACK-SAVE-DONE
493 ;; Cleanup the stack
494 (inst add esp-tn 8)
495
496 ;; Restore the new-stack.
497 (inst xor index index)
498 ;; First the stack-pointer.
499 (inst mov esp-tn
500 (make-ea :dword :base new-stack :index index :scale 4
501 :disp (- (* vm:vector-data-offset vm:word-bytes)
502 vm:other-pointer-type)))
503 (inst inc index)
bf84be07 504 (load-foreign-data-symbol stack "control_stack_end")
505 (inst mov stack (make-ea :dword :base stack))
5256503f 506 LOOP2
507 (inst cmp stack esp-tn)
508 (inst jmp :le STACK-RESTORE-DONE)
509 (inst sub stack 4)
510 (inst mov temp (make-ea :dword :base new-stack :index index :scale 4
511 :disp (- (* vm:vector-data-offset vm:word-bytes)
512 vm:other-pointer-type)))
513 (inst mov (make-ea :dword :base stack) temp)
514 (inst inc index)
515 (inst jmp-short LOOP2)
516 STACK-RESTORE-DONE
517 ;; Pop the frame pointer, and resume at the return address.
518 (inst pop ebp-tn)
519 (inst ret)
520
521 ;; Original thread resumes, stack has been cleaned up.
522 RETURN))
523
524
525(export 'control-stack-return)
526(defknown control-stack-return ((simple-array (unsigned-byte 32) (*)))
527 (values))
528
529(define-vop (control-stack-return)
530 (:policy :fast-safe)
531 (:translate control-stack-return)
532 (:args (new-stack :scs (descriptor-reg) :to :result))
533 (:arg-types simple-array-unsigned-byte-32)
534 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) index)
535 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) stack)
536 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) temp)
537 (:save-p t)
538 (:generator 25
539 ;; Restore the new-stack.
540 (inst xor index index)
541 ;; First the stack-pointer.
542 (inst mov esp-tn
543 (make-ea :dword :base new-stack :index index :scale 4
544 :disp (- (* vm:vector-data-offset vm:word-bytes)
545 vm:other-pointer-type)))
546 (inst inc index)
bf84be07 547 (load-foreign-data-symbol stack "control_stack_end")
548 (inst mov stack (make-ea :dword :base stack))
5256503f 549 LOOP
550 (inst cmp stack esp-tn)
551 (inst jmp :le STACK-RESTORE-DONE)
552 (inst sub stack 4)
553 (inst mov temp (make-ea :dword :base new-stack :index index :scale 4
554 :disp (- (* vm:vector-data-offset vm:word-bytes)
555 vm:other-pointer-type)))
556 (inst mov (make-ea :dword :base stack) temp)
557 (inst inc index)
558 (inst jmp-short LOOP)
559 STACK-RESTORE-DONE
560 ;; Pop the frame pointer, and resume at the return address.
561 (inst pop ebp-tn)
562 (inst ret)))
fe40afd6 563
564
8d75583b 565;; The RDTSC instruction (present on Pentium processors and
fe40afd6 566;; successors) allows you to access the time-stamp counter, a 64-bit
567;; model-specific register that counts executed cycles. The
568;; instruction returns the low cycle count in EAX and high cycle count
569;; in EDX.
570;;
571;; In order to obtain more significant results on out-of-order
572;; processors (such as the Pentium II and later), we issue a
573;; serializing CPUID instruction before reading the cycle counter.
574;; This instruction is used for its side effect of emptying the
575;; processor pipeline, to ensure that the RDTSC instruction is
576;; executed once all pending instructions have been completed.
577;;
578;; Note that cache effects mean that the cycle count can vary for
579;; different executions of the same code (it counts cycles, not
580;; retired instructions). Furthermore, the results are per-processor
581;; and not per-process, so are unreliable on multiprocessor machines
582;; where processes can migrate between processors.
583;;
584;; This method of obtaining a cycle count has the advantage of being
585;; very fast (around 20 cycles), and of not requiring a system call.
586;; However, you need to know your processor's clock speed to translate
587;; this into real execution time.
588
589(defknown read-cycle-counter () (values (unsigned-byte 32) (unsigned-byte 32)) ())
590
591(define-vop (read-cycle-counter)
592 (:translate read-cycle-counter)
593 (:guard (backend-featurep :pentium))
594 (:args )
595 (:policy :fast-safe)
596 (:results (lo :scs (unsigned-reg))
597 (hi :scs (unsigned-reg)))
598 (:result-types unsigned-num unsigned-num)
599 (:temporary (:sc unsigned-reg :offset eax-offset :target lo) eax)
600 (:temporary (:sc unsigned-reg :offset edx-offset :target hi) edx)
3832e020
RT
601 ;; CPUID writes to eax, ebx, ecx, and edx. We need temporaries for
602 ;; ebx and ecx so we don't destroy any live uses of ebx and ecx.
603 (:temporary (:sc unsigned-reg :offset ebx-offset
604 :from (:eval 0) :to (:result 1))
605 ebx)
606 (:temporary (:sc unsigned-reg :offset ecx-offset
607 :from (:eval 0) :to (:result 2))
608 ecx)
609 (:ignore ebx ecx)
fe40afd6 610 (:generator 1
3832e020
RT
611 (inst mov eax 0)
612 (inst cpuid)
613 (inst rdtsc)
614 (move hi edx)
615 (move lo eax)))
fe40afd6 616
617#+pentium
618(defun read-cycle-counter ()
619 (read-cycle-counter))
3c78ebec 620
621(defknown cpuid ((unsigned-byte 32))
622 (values (unsigned-byte 32)
623 (unsigned-byte 32)
624 (unsigned-byte 32)
625 (unsigned-byte 32))
626 ())
627
628(define-vop (cpuid)
629 (:policy :fast-safe)
630 (:translate cpuid)
b674af55 631 (:args (level :scs (unsigned-reg) :to (:eval 0)))
3c78ebec 632 (:arg-types unsigned-num)
633 (:results (a :scs (unsigned-reg))
634 (b :scs (unsigned-reg))
635 (c :scs (unsigned-reg))
636 (d :scs (unsigned-reg)))
637 (:result-types unsigned-num unsigned-num unsigned-num unsigned-num)
638 ;; Not sure about these :from/:to values.
639 (:temporary (:sc unsigned-reg :offset eax-offset
b674af55 640 :from (:eval 0) :to (:result 0))
3c78ebec 641 eax)
642 (:temporary (:sc unsigned-reg :offset ebx-offset
b674af55 643 :from (:eval 0) :to (:result 1))
3c78ebec 644 ebx)
645 (:temporary (:sc unsigned-reg :offset ecx-offset
b674af55 646 :from (:eval 0) :to (:result 2))
3c78ebec 647 ecx)
648 (:temporary (:sc unsigned-reg :offset edx-offset
b674af55 649 :from (:eval 0) :to (:result 3))
3c78ebec 650 edx)
b674af55 651 (:temporary (:sc unsigned-stack :from (:eval 0) :to (:result 0)) eax-stack)
652 (:temporary (:sc unsigned-stack :from (:eval 0) :to (:result 1)) ebx-stack)
653 (:temporary (:sc unsigned-stack :from (:eval 0) :to (:result 2)) ecx-stack)
654 (:temporary (:sc unsigned-stack :from (:eval 0) :to (:result 3)) edx-stack)
3c78ebec 655 (:generator 10
656 (move eax level)
657 (inst cpuid)
658 ;; Don't know where a, b, c, d are, so we save the results of
659 ;; cpuid to the stack and then copy the stack values to the result
b674af55 660 ;; registers. But we can skip this if the result registers match
661 ;; the output registers of the cpuid instruction.
662 (unless (and (location= eax a)
663 (location= ebx b)
664 (location= ecx c)
665 (location= edx d))
666 (move eax-stack eax)
667 (move ebx-stack ebx)
668 (move ecx-stack ecx)
669 (move edx-stack edx)
670 (move a eax-stack)
671 (move b ebx-stack)
672 (move c ecx-stack)
673 (move d edx-stack))))
3c78ebec 674
675
676(defun cpuid (level)
677 (declare (type (unsigned-byte 32) level))
678 (cpuid level))
8d75583b
RT
679
680(defmacro with-cycle-counter (&body body)
681 "Returns the primary value of BODY as the primary value, and the
682 number of CPU cycles elapsed as secondary value."
683 (let ((hi0 (gensym))
684 (hi1 (gensym))
685 (lo0 (gensym))
686 (lo1 (gensym)))
687 `(multiple-value-bind (,lo0 ,hi0)
688 (read-cycle-counter)
689 (values (locally ,@body)
690 (multiple-value-bind (,lo1 ,hi1)
691 (read-cycle-counter)
692 ;; Can't do anything about the notes about generic
693 ;; arithmetic, so silence the notes..
8391b8b0 694 (declare (optimize (inhibit-warnings 3)))
8d75583b
RT
695 (+ (ash (- ,hi1 ,hi0) 32)
696 (- ,lo1 ,lo0)))))))