1 ;;;; various useful macros for generating Sparc code
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 ;;; Instruction-like macros.
16 (defmacro move (dst src)
17 "Move SRC into DST unless they are location=."
18 (once-only ((n-dst dst)
20 `(unless (location= ,n-dst ,n-src)
21 (inst move ,n-dst ,n-src))))
24 ((frob (op inst shift)
25 `(defmacro ,op (object base &optional (offset 0) (lowtag 0))
26 `(inst ,',inst ,object ,base (- (ash ,offset ,,shift) ,lowtag)))))
27 (frob loadw ld word-shift)
28 (frob storew st word-shift))
30 (defmacro load-symbol (reg symbol)
31 `(inst add ,reg null-tn (static-symbol-offset ,symbol)))
35 (let ((loader (intern (concatenate 'simple-string
38 (storer (intern (concatenate 'simple-string
41 (offset (intern (concatenate 'simple-string
45 (find-package "SB!VM"))))
47 (defmacro ,loader (reg symbol)
48 `(inst ld ,reg null-tn
49 (+ (static-symbol-offset ',symbol)
50 (ash ,',offset word-shift)
51 (- other-pointer-lowtag))))
52 (defmacro ,storer (reg symbol)
53 `(inst st ,reg null-tn
54 (+ (static-symbol-offset ',symbol)
55 (ash ,',offset word-shift)
56 (- other-pointer-lowtag))))))))
60 (defmacro load-type (target source &optional (offset 0))
62 "Loads the type bits of a pointer into target independent of
63 byte-ordering issues."
64 (once-only ((n-target target)
67 ;; FIXME: although I don't understand entirely, I'm going to do
68 ;; what whn does in x86/macros.lisp -- Christophe
69 (ecase *backend-byte-order*
71 `(inst ldub ,n-target ,n-source ,n-offset))
73 `(inst ldub ,n-target ,n-source (+ ,n-offset 3))))))
75 ;;; Macros to handle the fact that we cannot use the machine native call and
76 ;;; return instructions.
78 (defmacro lisp-jump (fun)
79 "Jump to the lisp function FUNCTION. LIP is an interior-reg temporary."
82 (- (ash simple-fun-code-offset word-shift) fun-pointer-lowtag))
85 (defmacro lisp-return (return-pc &key (offset 0) (frob-code t))
86 "Return to RETURN-PC."
89 (- (* (1+ ,offset) n-word-bytes) other-pointer-lowtag))
91 `(move code-tn ,return-pc)
94 (defmacro emit-return-pc (label)
95 "Emit a return-pc header word. LABEL is the label to use for this return-pc."
99 (inst lra-header-word)))
105 ;;; Load-Stack-TN, Store-Stack-TN -- Interface
107 ;;; Move a stack TN to a register and vice-versa.
109 (defmacro load-stack-tn (reg stack)
112 (let ((offset (tn-offset stack)))
115 (loadw reg cfp-tn offset))))))
117 (defmacro store-stack-tn (stack reg)
118 `(let ((stack ,stack)
120 (let ((offset (tn-offset stack)))
123 (storew reg cfp-tn offset))))))
126 ;;; MAYBE-LOAD-STACK-TN -- Interface
128 (defmacro maybe-load-stack-tn (reg reg-or-stack)
129 "Move the TN Reg-Or-Stack into Reg if it isn't already there."
130 (once-only ((n-reg reg)
131 (n-stack reg-or-stack))
133 ((any-reg descriptor-reg)
135 ((any-reg descriptor-reg)
136 (move ,n-reg ,n-stack))
138 (loadw ,n-reg cfp-tn (tn-offset ,n-stack))))))))
141 ;;;; Storage allocation:
143 (defmacro with-fixed-allocation ((result-tn temp-tn type-code size)
145 "Do stuff to allocate an other-pointer object of fixed Size with a single
146 word header having the specified Type-Code. The result is placed in
147 Result-TN, and Temp-TN is a non-descriptor temp (which may be randomly used
148 by the body.) The body is placed inside the PSEUDO-ATOMIC, and presumably
149 initializes the object."
150 (once-only ((result-tn result-tn) (temp-tn temp-tn)
151 (type-code type-code) (size size))
152 `(pseudo-atomic (:extra (pad-data-block ,size))
153 (inst or ,result-tn alloc-tn other-pointer-lowtag)
154 (inst li ,temp-tn (logior (ash (1- ,size) n-widetag-bits) ,type-code))
155 (storew ,temp-tn ,result-tn 0 other-pointer-lowtag)
161 (defvar *adjustable-vectors* nil)
163 (defmacro with-adjustable-vector ((var) &rest body)
164 `(let ((,var (or (pop *adjustable-vectors*)
166 :element-type '(unsigned-byte 8)
169 (setf (fill-pointer ,var) 0)
173 (push ,var *adjustable-vectors*))))
175 (eval-when (:compile-toplevel :load-toplevel :execute)
176 (defun emit-error-break (vop kind code values)
177 (let ((vector (gensym)))
180 (note-this-location vop :internal-error)))
182 (with-adjustable-vector (,vector)
183 (write-var-integer (error-number-or-lose ',code) ,vector)
184 ,@(mapcar #'(lambda (tn)
186 (write-var-integer (make-sc-offset (sc-number
191 (inst byte (length ,vector))
192 (dotimes (i (length ,vector))
193 (inst byte (aref ,vector i))))
194 (align word-shift)))))
196 (defmacro error-call (vop error-code &rest values)
197 "Cause an error. ERROR-CODE is the error to cause."
199 (emit-error-break vop error-trap error-code values)))
202 (defmacro cerror-call (vop label error-code &rest values)
203 "Cause a continuable error. If the error is continued, execution resumes at
207 ,@(emit-error-break vop cerror-trap error-code values)))
209 (defmacro generate-error-code (vop error-code &rest values)
210 "Generate-Error-Code Error-code Value*
211 Emit code for an error with the specified Error-Code and context Values."
212 `(assemble (*elsewhere*)
213 (let ((start-lab (gen-label)))
214 (emit-label start-lab)
215 (error-call ,vop ,error-code ,@values)
218 (defmacro generate-cerror-code (vop error-code &rest values)
219 "Generate-CError-Code Error-code Value*
220 Emit code for a continuable error with the specified Error-Code and
221 context Values. If the error is continued, execution resumes after
222 the GENERATE-CERROR-CODE form."
223 (let ((continue (gensym "CONTINUE-LABEL-"))
224 (error (gensym "ERROR-LABEL-")))
225 `(let ((,continue (gen-label)))
226 (emit-label ,continue)
227 (assemble (*elsewhere*)
228 (let ((,error (gen-label)))
230 (cerror-call ,vop ,continue ,error-code ,@values)
235 ;;; PSEUDO-ATOMIC -- Handy macro for making sequences look atomic.
237 (defmacro pseudo-atomic ((&key (extra 0)) &rest forms)
238 (let ((n-extra (gensym)))
239 `(let ((,n-extra ,extra))
240 ;; Set the pseudo-atomic flag
241 (without-scheduling ()
242 (inst add alloc-tn 4))
244 ;; Reset the pseudo-atomic flag
245 (without-scheduling ()
246 #+nil (inst taddcctv alloc-tn (- ,n-extra 4))
247 ;; Remove the pseudo-atomic flag
248 (inst add alloc-tn (- ,n-extra 4))
249 ;; Check to see if pseudo-atomic interrupted flag is set (bit 0 = 1)
250 (inst andcc zero-tn alloc-tn 3)
251 ;; The C code needs to process this correctly and fixup alloc-tn.
252 (inst t :ne pseudo-atomic-trap)
255 ;;; FIXME: test typing macros. Should(?) be in type-vops.lisp, except
256 ;;; that they're also used in subprim.lisp
258 (defun cost-to-test-types (type-codes)
259 (+ (* 2 (length type-codes))
260 (if (> (apply #'max type-codes) lowtag-limit) 7 2)))
262 (defparameter *immediate-types*
263 (list base-char-widetag unbound-marker-widetag))
265 (defparameter *fun-header-widetags*
266 (list funcallable-instance-header-widetag
267 simple-fun-header-widetag
268 closure-fun-header-widetag
269 closure-header-widetag))
271 (defun gen-range-test (reg target not-target not-p min seperation max values)
276 (multiple-value-bind (equal less-or-equal greater-or-equal label)
278 (values :ne :gt :lt not-target)
279 (values :eq :le :ge target))
283 (push (cons start end) tests))))
284 (dolist (value values)
286 (error "~S is less than the specified minimum of ~S"
289 (error "~S is greater than the specified maximum of ~S"
291 ((not (zerop (rem (- value min) seperation)))
292 (error "~S isn't an even multiple of ~S from ~S"
293 value seperation min))
296 ((> value (+ end seperation))
301 (macrolet ((inst (name &rest args)
302 `(push (list 'inst ',name ,@args) insts)))
303 (do ((remaining (nreverse tests) (cdr remaining)))
305 (let ((test (car remaining))
306 (last (null (cdr remaining))))
311 (inst b equal target)
313 (let ((start (car test))
315 (cond ((and (= start min) (= end max))
316 (warn "The values ~S cover the entire range from ~
318 values min max seperation)
319 (push `(unless ,not-p (inst b ,target)) insts))
323 (inst b less-or-equal target)
328 (inst b greater-or-equal target)
332 (inst b :lt (if not-p target not-target))
335 (inst b less-or-equal target)
336 (inst b :le label))))))))))
339 (defun gen-other-immediate-test (reg target not-target not-p values)
340 (gen-range-test reg target not-target not-p
341 (+ other-immediate-0-lowtag lowtag-limit)
342 (- other-immediate-1-lowtag other-immediate-0-lowtag)
343 (ash 1 n-widetag-bits)
346 (defun test-type-aux (reg temp target not-target not-p lowtags immed hdrs
348 (let* ((fixnump (and (member even-fixnum-lowtag lowtags :test #'eql)
349 (member odd-fixnum-lowtag lowtags :test #'eql)))
350 (lowtags (sort (if fixnump
351 (delete even-fixnum-lowtag
352 (remove odd-fixnum-lowtag lowtags
357 (lowtag (if function-p
359 other-pointer-lowtag))
360 (hdrs (sort (copy-list hdrs) #'<))
361 (immed (sort (copy-list immed) #'<)))
364 `((inst and ,temp ,reg widetag-mask)
365 ,@(if (or fixnump lowtags hdrs)
366 (let ((fall-through (gensym)))
367 `((let (,fall-through (gen-label))
368 ,@(gen-other-immediate-test
369 temp (if not-p not-target target)
370 fall-through nil immed)
371 (emit-label ,fall-through))))
372 (gen-other-immediate-test temp target not-target not-p immed))))
374 `((inst andcc zero-tn ,reg fixnum-tag-mask)
375 ,(if (or lowtags hdrs)
376 `(inst b :eq ,(if not-p not-target target)
377 #!+sparc-v9 ,(if not-p :pn :pt))
378 `(inst b ,(if not-p :ne :eq) ,target
379 #!+sparc-v9 ,(if not-p :pn :pt)))))
380 (when (or lowtags hdrs)
381 `((inst and ,temp ,reg lowtag-mask)))
384 (let ((fall-through (gensym)))
385 `((let ((,fall-through (gen-label)))
386 ,@(gen-range-test temp (if not-p not-target target)
388 0 1 (1- lowtag-limit) lowtags)
389 (emit-label ,fall-through))))
390 (gen-range-test temp target not-target not-p 0 1
391 (1- lowtag-limit) lowtags)))
393 `((inst cmp ,temp ,lowtag)
394 (inst b :ne ,(if not-p target not-target)
395 #!+sparc-v9 ,(if not-p :pn :pt))
397 (load-type ,temp ,reg (- ,lowtag))
398 ,@(gen-other-immediate-test temp target not-target not-p hdrs))))))
400 (defmacro test-type (register temp target not-p &rest type-codes)
401 (let* ((type-codes (mapcar #'eval type-codes))
402 (lowtags (remove lowtag-limit type-codes :test #'<))
403 (extended (remove lowtag-limit type-codes :test #'>))
404 (immediates (intersection extended *immediate-types* :test #'eql))
405 (headers (set-difference extended *immediate-types* :test #'eql))
408 (error "Must supply at least on type for test-type."))
409 (when (and headers (member other-pointer-lowtag lowtags))
410 (warn "OTHER-POINTER-TYPE supersedes the use of ~S" headers)
412 (when (and immediates
413 (or (member other-immediate-0-lowtag lowtags)
414 (member other-immediate-1-lowtag lowtags)))
415 (warn "OTHER-IMMEDIATE-n-TYPE supersedes the use of ~S" immediates)
416 (setf immediates nil))
417 (when (intersection headers *fun-header-widetags*)
418 (unless (subsetp headers *fun-header-widetags*)
419 (error "Can't test for mix of function subtypes and normal ~
423 (let ((n-reg (gensym))
426 (not-target (gensym)))
427 `(let ((,n-reg ,register)
430 (,not-target (gen-label)))
431 (declare (ignorable ,n-temp))
432 ,@(if (constantp not-p)
433 (test-type-aux n-reg n-temp n-target not-target
434 (eval not-p) lowtags immediates headers
437 ,@(test-type-aux n-reg n-temp n-target not-target t
438 lowtags immediates headers
441 ,@(test-type-aux n-reg n-temp n-target not-target nil
442 lowtags immediates headers
445 (emit-label ,not-target)))))