1 ;;;; miscellaneous VM definition noise for the x86
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.
16 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
17 (defvar *byte-register-names
* (make-array 8 :initial-element nil
))
18 (defvar *word-register-names
* (make-array 16 :initial-element nil
))
19 (defvar *dword-register-names
* (make-array 16 :initial-element nil
))
20 (defvar *float-register-names
* (make-array 8 :initial-element nil
)))
22 (macrolet ((defreg (name offset size
)
23 (let ((offset-sym (symbolicate name
"-OFFSET"))
24 (names-vector (symbolicate "*" size
"-REGISTER-NAMES*")))
26 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
27 ;; EVAL-WHEN is necessary because stuff like #.EAX-OFFSET
28 ;; (in the same file) depends on compile-time evaluation
29 ;; of the DEFCONSTANT. -- AL 20010224
30 (def!constant
,offset-sym
,offset
))
31 (setf (svref ,names-vector
,offset-sym
)
32 ,(symbol-name name
)))))
33 ;; FIXME: It looks to me as though DEFREGSET should also
34 ;; define the related *FOO-REGISTER-NAMES* variable.
35 (defregset (name &rest regs
)
36 `(eval-when (:compile-toplevel
:load-toplevel
:execute
)
38 (list ,@(mapcar (lambda (name)
39 (symbolicate name
"-OFFSET"))
44 ;; Note: the encoding here is different than that used by the chip.
45 ;; We use this encoding so that the compiler thinks that AX (and
46 ;; EAX) overlap AL and AH instead of AL and CL.
55 (defregset *byte-regs
* al ah cl ch dl dh bl bh
)
66 (defregset *word-regs
* ax cx dx bx si di
)
68 ;; double word registers
74 (defreg ebp
10 :dword
)
75 (defreg esi
12 :dword
)
76 (defreg edi
14 :dword
)
77 (defregset *dword-regs
* eax ecx edx ebx esi edi
)
79 ;; floating point registers
88 (defregset *float-regs
* fr0 fr1 fr2 fr3 fr4 fr5 fr6 fr7
)
90 ;; registers used to pass arguments
92 ;; the number of arguments/return values passed in registers
93 (def!constant register-arg-count
3)
94 ;; names and offsets for registers used to pass arguments
95 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
96 (defparameter *register-arg-names
* '(edx edi esi
)))
97 (defregset *register-arg-offsets
* edx edi esi
))
101 ;;; Despite the fact that there are only 8 different registers, we consider
102 ;;; them 16 in order to describe the overlap of byte registers. The only
103 ;;; thing we need to represent is what registers overlap. Therefore, we
104 ;;; consider bytes to take one unit, and words or dwords to take two. We
105 ;;; don't need to tell the difference between words and dwords, because
106 ;;; you can't put two words in a dword register.
107 (define-storage-base registers
:finite
:size
16)
109 ;;; jrd changed this from size 1 to size 8. It doesn't seem to make much
110 ;;; sense to use the 387's idea of a stack; 8 separate registers is easier
113 ;;; (define-storage-base float-registers :finite :size 1)
115 (define-storage-base float-registers
:finite
:size
8)
117 (define-storage-base stack
:unbounded
:size
3 :size-increment
1)
118 (define-storage-base constant
:non-packed
)
119 (define-storage-base immediate-constant
:non-packed
)
120 (define-storage-base noise
:unbounded
:size
2)
124 ;;; a handy macro so we don't have to keep changing all the numbers whenever
125 ;;; we insert a new storage class
127 (defmacro !define-storage-classes
(&rest classes
)
130 (dolist (class classes
)
131 (let* ((sc-name (car class
))
132 (constant-name (symbolicate sc-name
"-SC-NUMBER")))
133 (forms `(define-storage-class ,sc-name
,index
135 (forms `(def!constant
,constant-name
,index
))
140 (!define-storage-classes
142 ;; non-immediate constants in the constant pool
145 ;; some FP constants can be generated in the i387 silicon
146 (fp-constant immediate-constant
)
147 (fp-single-immediate immediate-constant
)
148 (fp-double-immediate immediate-constant
)
149 (immediate immediate-constant
)
156 (control-stack stack
) ; may be pointers, scanned by GC
158 ;; the non-descriptor stacks
159 (signed-stack stack
) ; (signed-byte 32)
160 (unsigned-stack stack
) ; (unsigned-byte 32)
161 (character-stack stack
) ; non-descriptor characters.
162 (sap-stack stack
) ; System area pointers.
163 (single-stack stack
) ; single-floats
164 (double-stack stack
:element-size
2) ; double-floats.
166 (long-stack stack
:element-size
3) ; long-floats.
167 (complex-single-stack stack
:element-size
2) ; complex-single-floats
168 (complex-double-stack stack
:element-size
4) ; complex-double-floats
170 (complex-long-stack stack
:element-size
6) ; complex-long-floats
179 ;; things that can go in the integer registers
182 ;; On the X86, we don't have to distinguish between descriptor and
183 ;; non-descriptor registers, because of the conservative GC.
184 ;; Therefore, we use different scs only to distinguish between
185 ;; descriptor and non-descriptor values and to specify size.
187 ;; immediate descriptor objects. Don't have to be seen by GC, but nothing
188 ;; bad will happen if they are. (fixnums, characters, header values, etc).
190 :locations
#.
*dword-regs
*
192 ; :reserve-locations (#.eax-offset)
193 :constant-scs
(immediate)
195 :alternate-scs
(control-stack))
197 ;; pointer descriptor objects -- must be seen by GC
198 (descriptor-reg registers
199 :locations
#.
*dword-regs
*
201 ; :reserve-locations (#.eax-offset)
202 :constant-scs
(constant immediate
)
204 :alternate-scs
(control-stack))
206 ;; non-descriptor characters
207 (character-reg registers
208 :locations
#!-sb-unicode
#.
*byte-regs
*
209 #!+sb-unicode
#.
*dword-regs
*
210 #!+sb-unicode
#!+sb-unicode
212 #!-sb-unicode
#!-sb-unicode
213 :reserve-locations
(#.ah-offset
#.al-offset
)
214 :constant-scs
(immediate)
216 :alternate-scs
(character-stack))
218 ;; non-descriptor SAPs (arbitrary pointers into address space)
220 :locations
#.
*dword-regs
*
222 ; :reserve-locations (#.eax-offset)
223 :constant-scs
(immediate)
225 :alternate-scs
(sap-stack))
227 ;; non-descriptor (signed or unsigned) numbers
228 (signed-reg registers
229 :locations
#.
*dword-regs
*
231 ; :reserve-locations (#.eax-offset)
232 :constant-scs
(immediate)
234 :alternate-scs
(signed-stack))
235 (unsigned-reg registers
236 :locations
#.
*dword-regs
*
238 ; :reserve-locations (#.eax-offset)
239 :constant-scs
(immediate)
241 :alternate-scs
(unsigned-stack))
243 ;; miscellaneous objects that must not be seen by GC. Used only as
246 :locations
#.
*word-regs
*
248 ; :reserve-locations (#.ax-offset)
251 :locations
#.
*byte-regs
*
252 ; :reserve-locations (#.al-offset #.ah-offset)
255 ;; that can go in the floating point registers
257 ;; non-descriptor SINGLE-FLOATs
258 (single-reg float-registers
259 :locations
(0 1 2 3 4 5 6 7)
260 :constant-scs
(fp-constant fp-single-immediate
)
262 :alternate-scs
(single-stack))
264 ;; non-descriptor DOUBLE-FLOATs
265 (double-reg float-registers
266 :locations
(0 1 2 3 4 5 6 7)
267 :constant-scs
(fp-constant fp-double-immediate
)
269 :alternate-scs
(double-stack))
271 ;; non-descriptor LONG-FLOATs
273 (long-reg float-registers
274 :locations
(0 1 2 3 4 5 6 7)
275 :constant-scs
(fp-constant)
277 :alternate-scs
(long-stack))
279 (complex-single-reg float-registers
284 :alternate-scs
(complex-single-stack))
286 (complex-double-reg float-registers
291 :alternate-scs
(complex-double-stack))
294 (complex-long-reg float-registers
299 :alternate-scs
(complex-long-stack))
301 ;; a catch or unwind block
302 (catch-block stack
:element-size catch-block-size
))
304 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
305 (defparameter *byte-sc-names
*
306 '(#!-sb-unicode character-reg byte-reg
#!-sb-unicode character-stack
))
307 (defparameter *word-sc-names
* '(word-reg))
308 (defparameter *dword-sc-names
*
309 '(any-reg descriptor-reg sap-reg signed-reg unsigned-reg control-stack
310 signed-stack unsigned-stack sap-stack single-stack
311 #!+sb-unicode character-reg
#!+sb-unicode character-stack constant
))
312 ;;; added by jrd. I guess the right thing to do is to treat floats
313 ;;; as a separate size...
315 ;;; These are used to (at least) determine operand size.
316 (defparameter *float-sc-names
* '(single-reg))
317 (defparameter *double-sc-names
* '(double-reg double-stack
))
320 ;;;; miscellaneous TNs for the various registers
322 (macrolet ((def-misc-reg-tns (sc-name &rest reg-names
)
324 (dolist (reg-name reg-names
)
325 (let ((tn-name (symbolicate reg-name
"-TN"))
326 (offset-name (symbolicate reg-name
"-OFFSET")))
327 ;; FIXME: It'd be good to have the special
328 ;; variables here be named with the *FOO*
330 (forms `(defparameter ,tn-name
331 (make-random-tn :kind
:normal
332 :sc
(sc-or-lose ',sc-name
)
335 `(progn ,@(forms)))))
337 (def-misc-reg-tns unsigned-reg eax ebx ecx edx ebp esp edi esi
)
338 (def-misc-reg-tns word-reg ax bx cx dx bp sp di si
)
339 (def-misc-reg-tns byte-reg al ah bl bh cl ch dl dh
)
340 (def-misc-reg-tns single-reg fr0 fr1 fr2 fr3 fr4 fr5 fr6 fr7
))
342 ;;; TNs for registers used to pass arguments
343 (defparameter *register-arg-tns
*
344 (mapcar (lambda (register-arg-name)
345 (symbol-value (symbolicate register-arg-name
"-TN")))
346 *register-arg-names
*))
348 ;;; FIXME: doesn't seem to be used in SBCL
351 (defparameter fp-constant-tn
352 (make-random-tn :kind
:normal
353 :sc
(sc-or-lose 'fp-constant
)
354 :offset
31)) ; Offset doesn't get used.
357 ;;; If value can be represented as an immediate constant, then return
358 ;;; the appropriate SC number, otherwise return NIL.
359 (defun immediate-constant-sc (value)
361 ((or (integer #.sb
!xc
:most-negative-fixnum
#.sb
!xc
:most-positive-fixnum
)
363 (sc-number-or-lose 'immediate
))
365 (when (static-symbol-p value
)
366 (sc-number-or-lose 'immediate
)))
369 ((0f0 1f0
) (sc-number-or-lose 'fp-constant
))
370 (t (sc-number-or-lose 'fp-single-immediate
))))
373 ((0d0 1d0
) (sc-number-or-lose 'fp-constant
))
374 (t (sc-number-or-lose 'fp-double-immediate
))))
377 (when (or (eql value
0l0) (eql value
1l0)
379 (eql value
(log 10l0 2l0))
380 (eql value
(log 2.718281828459045235360287471352662L0 2l0))
381 (eql value
(log 2l0 10l0))
382 (eql value
(log 2l0 2.718281828459045235360287471352662L0)))
383 (sc-number-or-lose 'fp-constant
)))))
385 (defun boxed-immediate-sc-p (sc)
386 (eql sc
(sc-number-or-lose 'immediate
)))
388 ;; For an immediate TN, return its value encoded for use as a literal.
389 ;; For any other TN, return the TN. Only works for FIXNUMs,
390 ;; STATIC-SYMBOLs, and CHARACTERS (FLOATs and SAPs are handled
392 (defun encode-value-if-immediate (tn)
393 (if (sc-is tn immediate
)
394 (let ((val (tn-value tn
)))
396 (integer (fixnumize val
))
397 (symbol (+ nil-value
(static-symbol-offset val
)))
398 (character (logior (ash (char-code val
) n-widetag-bits
)
399 character-widetag
))))
402 ;;;; miscellaneous function call parameters
404 ;;; Offsets of special stack frame locations relative to EBP.
406 ;;; Consider the standard prologue PUSH EBP; MOV EBP, ESP: the return
407 ;;; address is at EBP+4, the old control stack frame pointer is at
408 ;;; EBP, the magic 3rd slot is at EBP-4. Then come the locals from
410 (def!constant return-pc-save-offset
0)
411 (def!constant ocfp-save-offset
1)
412 ;;; Let SP be the stack pointer before CALLing, and FP is the frame
413 ;;; pointer after the standard prologue. SP +
414 ;;; FRAME-WORD-OFFSET(SP->FP-OFFSET + I) = FP + FRAME-WORD-OFFSET(I).
415 (def!constant sp-
>fp-offset
2)
417 (declaim (inline frame-word-offset
))
418 (defun frame-word-offset (index)
421 (declaim (inline frame-byte-offset
))
422 (defun frame-byte-offset (index)
423 (* (frame-word-offset index
) n-word-bytes
))
425 ;;; FIXME: This is a bad comment (changed since when?) and there are others
426 ;;; like it in this file. It'd be nice to clarify them. Failing that deleting
427 ;;; them or flagging them with KLUDGE might be better than nothing.
429 ;;; names of these things seem to have changed. these aliases by jrd
430 (def!constant lra-save-offset return-pc-save-offset
)
432 (def!constant cfp-offset ebp-offset
) ; pfw - needed by stuff in /code
433 ; related to signal context stuff
435 ;;; This is used by the debugger.
436 (def!constant single-value-return-byte-offset
2)
438 ;;; This function is called by debug output routines that want a pretty name
439 ;;; for a TN's location. It returns a thing that can be printed with PRINC.
440 (defun location-print-name (tn)
441 (declare (type tn tn
))
442 (let* ((sc (tn-sc tn
))
443 (sb (sb-name (sc-sb sc
)))
444 (offset (tn-offset tn
)))
447 (let* ((sc-name (sc-name sc
))
448 (name-vec (cond ((member sc-name
*byte-sc-names
*)
449 *byte-register-names
*)
450 ((member sc-name
*word-sc-names
*)
451 *word-register-names
*)
452 ((member sc-name
*dword-sc-names
*)
453 *dword-register-names
*))))
455 (< -
1 offset
(length name-vec
))
456 (svref name-vec offset
))
457 ;; FIXME: Shouldn't this be an ERROR?
458 (format nil
"<unknown reg: off=~W, sc=~A>" offset sc-name
))))
459 (float-registers (format nil
"FR~D" offset
))
460 (stack (format nil
"S~D" offset
))
461 (constant (format nil
"Const~D" offset
))
462 (immediate-constant "Immed")
463 (noise (symbol-name (sc-name sc
))))))
464 ;;; FIXME: Could this, and everything that uses it, be made #!+SB-SHOW?
466 (defun combination-implementation-style (node)
467 (declare (type sb
!c
::combination node
))
468 (flet ((valid-funtype (args result
)
469 (sb!c
::valid-fun-use node
470 (sb!c
::specifier-type
471 `(function ,args
,result
)))))
472 (case (sb!c
::combination-fun-source-name node
)
475 ((valid-funtype '(fixnum fixnum
) '*)
477 ((valid-funtype '((signed-byte 32) (signed-byte 32)) '*)
479 ((valid-funtype '((unsigned-byte 32) (unsigned-byte 32)) '*)
481 (t (values :default nil
))))
484 ((and (valid-funtype '((integer 0 29) fixnum
) '*)
485 (sb!c
::constant-lvar-p
(first (sb!c
::basic-combination-args node
))))
486 (values :transform
'(lambda (index integer
)
487 (%logbitp integer index
))))
488 ((valid-funtype '((integer 0 31) (signed-byte 32)) '*)
489 (values :transform
'(lambda (index integer
)
490 (%logbitp integer index
))))
491 ((valid-funtype '((integer 0 31) (unsigned-byte 32)) '*)
492 (values :transform
'(lambda (index integer
)
493 (%logbitp integer index
))))
494 (t (values :default nil
))))
495 (t (values :default nil
)))))