1 ;;; -*- Package: ALPHA; Log: C.Log -*-
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.
9 ;;; **********************************************************************
11 ;;; This file contains various useful macros for generating Alpha code.
13 ;;; Written by William Lott and Christopher Hoover.
14 ;;; Alpha conversion by Sean Hallgren.
20 ;;; Handy macro for defining top-level forms that depend on the compile
23 (defmacro expand (expr)
24 (let ((gensym (gensym)))
31 ;;; Instruction-like macros.
34 ;;(defmacro move (dst src)
36 ;; "Move SRC into DST unless they are location=."
37 ;; (once-only ((n-dst dst)
39 ;; `(unless (location= ,n-dst ,n-src)
40 ;; (inst mov ,n-dst ,n-src))))
43 (defmacro move (src dst)
44 "Move SRC into DST unless they are location=."
45 (once-only ((n-src src) (n-dst dst))
46 `(unless (location= ,n-src ,n-dst)
47 (inst move ,n-src ,n-dst))))
49 (defmacro loadw (result base &optional (offset 0) (lowtag 0))
50 (once-only ((result result) (base base))
51 `(inst ldl ,result (- (ash ,offset word-shift) ,lowtag) ,base)))
53 (defmacro loadq (result base &optional (offset 0) (lowtag 0))
54 (once-only ((result result) (base base))
55 `(inst ldq ,result (- (ash ,offset word-shift) ,lowtag) ,base)))
57 (defmacro storew (value base &optional (offset 0) (lowtag 0))
58 (once-only ((value value) (base base) (offset offset) (lowtag lowtag))
59 `(inst stl ,value (- (ash ,offset word-shift) ,lowtag) ,base)))
61 (defmacro storeq (value base &optional (offset 0) (lowtag 0))
62 (once-only ((value value) (base base) (offset offset) (lowtag lowtag))
63 `(inst stq ,value (- (ash ,offset word-shift) ,lowtag) ,base)))
65 (defmacro load-symbol (reg symbol)
66 (once-only ((reg reg) (symbol symbol))
67 `(inst lda ,reg (static-symbol-offset ,symbol) null-tn)))
69 (defmacro load-symbol-value (reg symbol)
71 (+ (static-symbol-offset ',symbol)
72 (ash symbol-value-slot word-shift)
73 (- other-pointer-type))
76 (defmacro store-symbol-value (reg symbol)
78 (+ (static-symbol-offset ',symbol)
79 (ash symbol-value-slot word-shift)
80 (- other-pointer-type))
83 (defmacro load-type (target source &optional (offset 0))
84 "Loads the type bits of a pointer into target independent of
85 byte-ordering issues."
86 (once-only ((n-target target)
90 (inst ldl ,n-target ,n-offset ,n-source)
91 (inst and ,n-target #xff ,n-target))))
93 ;;; Macros to handle the fact that we cannot use the machine native call and
94 ;;; return instructions.
96 (defmacro lisp-jump (function lip)
97 "Jump to the lisp function FUNCTION. LIP is an interior-reg temporary."
99 (inst lda ,lip (- (ash sb!vm:function-code-offset sb!vm:word-shift)
100 sb!vm:function-pointer-type)
102 (move ,function code-tn)
103 (inst jsr zero-tn ,lip 1)))
105 (defmacro lisp-return (return-pc lip &key (offset 0) (frob-code t))
106 "Return to RETURN-PC. LIP is an interior-reg temporary."
109 (- (* (1+ ,offset) word-bytes) other-pointer-type)
112 `((move ,return-pc code-tn)))
113 (inst ret zero-tn ,lip 1)))
116 (defmacro emit-return-pc (label)
117 "Emit a return-pc header word. LABEL is the label to use for this
122 (inst lra-header-word)))
128 ;;; Load-Stack-TN, Store-Stack-TN -- Interface
130 ;;; Move a stack TN to a register and vice-versa.
132 (defmacro load-stack-tn (reg stack)
135 (let ((offset (tn-offset stack)))
138 (loadw reg cfp-tn offset))))))
140 (defmacro store-stack-tn (stack reg)
141 `(let ((stack ,stack)
143 (let ((offset (tn-offset stack)))
146 (storew reg cfp-tn offset))))))
149 ;;; MAYBE-LOAD-STACK-TN -- Interface
151 (defmacro maybe-load-stack-tn (reg reg-or-stack)
152 "Move the TN Reg-Or-Stack into Reg if it isn't already there."
153 (once-only ((n-reg reg)
154 (n-stack reg-or-stack))
156 ((any-reg descriptor-reg)
158 ((any-reg descriptor-reg)
159 (move ,n-stack ,n-reg))
161 (loadw ,n-reg cfp-tn (tn-offset ,n-stack))))))))
163 ;;; MAYBE-LOAD-STACK-NFP-TN -- Interface
165 (defmacro maybe-load-stack-nfp-tn (reg reg-or-stack temp)
166 "Move the TN Reg-Or-Stack into Reg if it isn't already there."
167 (once-only ((n-reg reg)
168 (n-stack reg-or-stack))
171 ((any-reg descriptor-reg)
173 ((any-reg descriptor-reg)
174 (move ,n-stack ,n-reg))
176 (loadw ,n-reg cfp-tn (tn-offset ,n-stack))
177 (inst mskll nsp-tn 0 ,temp)
178 (inst bis ,temp ,n-reg ,n-reg))))))))
182 ;;;; Storage allocation:
184 (defmacro with-fixed-allocation ((result-tn temp-tn type-code size)
186 "Do stuff to allocate an other-pointer object of fixed Size with a single
187 word header having the specified Type-Code. The result is placed in
188 Result-TN, Flag-Tn must be wired to NL3-OFFSET, and Temp-TN is a non-
189 descriptor temp (which may be randomly used by the body.) The body is
190 placed inside the PSEUDO-ATOMIC, and presumably initializes the object."
191 `(pseudo-atomic (:extra (pad-data-block ,size))
192 (inst bis alloc-tn other-pointer-type ,result-tn)
193 (inst li (logior (ash (1- ,size) type-bits) ,type-code) ,temp-tn)
194 (storew ,temp-tn ,result-tn 0 other-pointer-type)
202 (defvar *adjustable-vectors* nil)
204 (defmacro with-adjustable-vector ((var) &rest body)
205 `(let ((,var (or (pop *adjustable-vectors*)
207 :element-type '(unsigned-byte 8)
210 (setf (fill-pointer ,var) 0)
214 (push ,var *adjustable-vectors*))))
216 (eval-when (:compile-toplevel :load-toplevel :execute)
217 (defun emit-error-break (vop kind code values)
218 (let ((vector (gensym)))
221 (note-this-location vop :internal-error)))
223 (with-adjustable-vector (,vector)
224 (write-var-integer (error-number-or-lose ',code) ,vector)
225 ,@(mapcar #'(lambda (tn)
227 (write-var-integer (make-sc-offset (sc-number
232 (inst byte (length ,vector))
233 (dotimes (i (length ,vector))
234 (inst byte (aref ,vector i))))
235 (align word-shift)))))
237 (defmacro error-call (vop error-code &rest values)
238 "Cause an error. ERROR-CODE is the error to cause."
240 (emit-error-break vop error-trap error-code values)))
243 (defmacro cerror-call (vop label error-code &rest values)
244 "Cause a continuable error. If the error is continued, execution resumes at
247 (inst br zero-tn ,label)
248 ,@(emit-error-break vop cerror-trap error-code values)))
250 (defmacro generate-error-code (vop error-code &rest values)
251 "Generate-Error-Code Error-code Value*
252 Emit code for an error with the specified Error-Code and context Values."
253 `(assemble (*elsewhere*)
254 (let ((start-lab (gen-label)))
255 (emit-label start-lab)
256 (error-call ,vop ,error-code ,@values)
259 (defmacro generate-cerror-code (vop error-code &rest values)
260 "Generate-CError-Code Error-code Value*
261 Emit code for a continuable error with the specified Error-Code and
262 context Values. If the error is continued, execution resumes after
263 the GENERATE-CERROR-CODE form."
264 (let ((continue (gensym "CONTINUE-LABEL-"))
265 (error (gensym "ERROR-LABEL-")))
266 `(let ((,continue (gen-label)))
267 (emit-label ,continue)
268 (assemble (*elsewhere*)
269 (let ((,error (gen-label)))
271 (cerror-call ,vop ,continue ,error-code ,@values)
275 ;;; PSEUDO-ATOMIC -- Handy macro for making sequences look atomic.
277 (defmacro pseudo-atomic ((&key (extra 0)) &rest forms)
279 (inst addq alloc-tn 1 alloc-tn)
281 (inst lda alloc-tn (1- ,extra) alloc-tn)
282 (inst stl zero-tn 0 alloc-tn)))
286 ;;;; Memory accessor vop generators
288 (deftype load/store-index (scale lowtag min-offset
289 &optional (max-offset min-offset))
290 `(integer ,(- (truncate (+ (ash 1 16)
291 (* min-offset word-bytes)
294 ,(truncate (- (+ (1- (ash 1 16)) lowtag)
295 (* max-offset word-bytes))
298 (defmacro define-full-reffer (name type offset lowtag scs el-type
303 `((:translate ,translate)))
305 (:args (object :scs (descriptor-reg))
306 (index :scs (any-reg)))
307 (:arg-types ,type tagged-num)
308 (:temporary (:scs (interior-reg)) lip)
309 (:results (value :scs ,scs))
310 (:result-types ,el-type)
312 (inst addq object index lip)
313 (inst ldl value (- (* ,offset word-bytes) ,lowtag) lip)
314 ,@(when (equal scs '(unsigned-reg))
315 '((inst mskll value 4 value)))))
316 (define-vop (,(symbolicate name "-C"))
318 `((:translate ,translate)))
320 (:args (object :scs (descriptor-reg)))
323 (:constant (load/store-index ,word-bytes ,(eval lowtag)
325 (:results (value :scs ,scs))
326 (:result-types ,el-type)
328 (inst ldl value (- (* (+ ,offset index) word-bytes) ,lowtag)
330 ,@(when (equal scs '(unsigned-reg))
331 '((inst mskll value 4 value)))))))
333 (defmacro define-full-setter (name type offset lowtag scs el-type
334 &optional translate #+gengc (remember t))
338 `((:translate ,translate)))
340 (:args (object :scs (descriptor-reg))
341 (index :scs (any-reg))
342 (value :scs ,scs :target result))
343 (:arg-types ,type tagged-num ,el-type)
344 (:temporary (:scs (interior-reg)) lip)
345 (:results (result :scs ,scs))
346 (:result-types ,el-type)
348 (inst addq index object lip)
349 (inst stl value (- (* ,offset word-bytes) ,lowtag) lip)
350 (move value result)))
351 (define-vop (,(symbolicate name "-C"))
353 `((:translate ,translate)))
355 (:args (object :scs (descriptor-reg))
359 (:constant (load/store-index ,word-bytes ,(eval lowtag)
362 (:results (result :scs ,scs))
363 (:result-types ,el-type)
365 (inst stl value (- (* (+ ,offset index) word-bytes) ,lowtag)
367 (move value result)))))
370 (defmacro define-partial-reffer (name type size signed offset lowtag scs
371 el-type &optional translate)
372 (let ((scale (ecase size (:byte 1) (:short 2))))
376 `((:translate ,translate)))
378 (:args (object :scs (descriptor-reg))
379 (index :scs (unsigned-reg)))
380 (:arg-types ,type positive-fixnum)
381 (:results (value :scs ,scs))
382 (:result-types ,el-type)
383 (:temporary (:scs (interior-reg)) lip)
384 (:temporary (:sc non-descriptor-reg) temp)
385 (:temporary (:sc non-descriptor-reg) temp1)
387 (inst addq object index lip)
388 ,@(when (eq size :short)
389 '((inst addq index lip lip)))
393 `((inst ldq_u temp (- (* ,offset word-bytes) ,lowtag)
395 (inst lda temp1 (1+ (- (* ,offset word-bytes) ,lowtag))
397 (inst extqh temp temp1 temp)
398 (inst sra temp 56 value))
399 `((inst ldq_u temp (- (* ,offset word-bytes) ,lowtag) lip)
400 (inst lda temp1 (- (* ,offset word-bytes) ,lowtag)
402 (inst extbl temp temp1 value))))
405 `((inst ldq_u temp (- (* ,offset word-bytes) ,lowtag)
407 (inst lda temp1 (- (* ,offset word-bytes) ,lowtag)
409 (inst extwl temp temp1 temp)
410 (inst sll temp 48 temp)
411 (inst sra temp 48 value))
412 `((inst ldq_u temp (- (* ,offset word-bytes) ,lowtag)
414 (inst lda temp1 (- (* ,offset word-bytes) ,lowtag) lip)
415 (inst extwl temp temp1 value)))))))
416 (define-vop (,(symbolicate name "-C"))
418 `((:translate ,translate)))
420 (:args (object :scs (descriptor-reg)))
423 (:constant (load/store-index ,scale
426 (:results (value :scs ,scs))
427 (:result-types ,el-type)
428 (:temporary (:sc non-descriptor-reg) temp)
429 (:temporary (:sc non-descriptor-reg) temp1)
434 `((inst ldq_u temp (- (+ (* ,offset word-bytes)
435 (* index ,scale)) ,lowtag)
437 (inst lda temp1 (1+ (- (+ (* ,offset word-bytes)
438 (* index ,scale)) ,lowtag))
440 (inst extqh temp temp1 temp)
441 (inst sra temp 56 value))
442 `((inst ldq_u temp (- (+ (* ,offset word-bytes)
443 (* index ,scale)) ,lowtag)
445 (inst lda temp1 (- (+ (* ,offset word-bytes)
446 (* index ,scale)) ,lowtag)
448 (inst extbl temp temp1 value))))
451 `((inst ldq_u temp (- (+ (* ,offset word-bytes)
452 (* index ,scale)) ,lowtag)
454 (inst lda temp1 (- (+ (* ,offset word-bytes)
455 (* index ,scale)) ,lowtag)
457 (inst extwl temp temp1 temp)
458 (inst sll temp 48 temp)
459 (inst sra temp 48 value))
460 `((inst ldq_u temp (- (+ (* ,offset word-bytes)
461 (* index ,scale)) ,lowtag)
463 (inst lda temp1 (- (+ (* ,offset word-bytes)
464 (* index ,scale)) ,lowtag)
466 (inst extwl temp temp1 value))))))))))
468 (defmacro define-partial-setter (name type size offset lowtag scs el-type
470 (let ((scale (ecase size (:byte 1) (:short 2))))
474 `((:translate ,translate)))
476 (:args (object :scs (descriptor-reg))
477 (index :scs (unsigned-reg))
478 (value :scs ,scs :target result))
479 (:arg-types ,type positive-fixnum ,el-type)
480 (:temporary (:scs (interior-reg)) lip)
481 (:temporary (:sc non-descriptor-reg) temp)
482 (:temporary (:sc non-descriptor-reg) temp1)
483 (:temporary (:sc non-descriptor-reg) temp2)
484 (:results (result :scs ,scs))
485 (:result-types ,el-type)
487 (inst addq object index lip)
488 ,@(when (eq size :short)
489 '((inst addq lip index lip)))
492 `((inst lda temp (- (* ,offset word-bytes) ,lowtag) lip)
493 (inst ldq_u temp1 (- (* ,offset word-bytes) ,lowtag) lip)
494 (inst insbl value temp temp2)
495 (inst mskbl temp1 temp temp1)
496 (inst bis temp1 temp2 temp1)
497 (inst stq_u temp1 (- (* ,offset word-bytes) ,lowtag) lip)))
499 `((inst lda temp (- (* ,offset word-bytes) ,lowtag) lip)
500 (inst ldq_u temp1 (- (* ,offset word-bytes) ,lowtag) lip)
501 (inst mskwl temp1 temp temp1)
502 (inst inswl value temp temp2)
503 (inst bis temp1 temp2 temp)
504 (inst stq_u temp (- (* ,offset word-bytes) ,lowtag) lip))))
505 (move value result)))
506 (define-vop (,(symbolicate name "-C"))
508 `((:translate ,translate)))
510 (:args (object :scs (descriptor-reg))
511 (value :scs ,scs :target result))
514 (:constant (load/store-index ,scale
518 (:temporary (:sc non-descriptor-reg) temp)
519 (:temporary (:sc non-descriptor-reg) temp1)
520 (:temporary (:sc non-descriptor-reg) temp2)
521 (:results (result :scs ,scs))
522 (:result-types ,el-type)
526 `((inst lda temp (- (* ,offset word-bytes)
527 (* index ,scale) ,lowtag)
529 (inst ldq_u temp1 (- (* ,offset word-bytes)
530 (* index ,scale) ,lowtag)
532 (inst insbl value temp temp2)
533 (inst mskbl temp1 temp temp1)
534 (inst bis temp1 temp2 temp1)
535 (inst stq_u temp1 (- (* ,offset word-bytes)
536 (* index ,scale) ,lowtag) object)))
538 `((inst lda temp (- (* ,offset word-bytes)
539 (* index ,scale) ,lowtag)
541 (inst ldq_u temp1 (- (* ,offset word-bytes)
542 (* index ,scale) ,lowtag)
544 (inst mskwl temp1 temp temp1)
545 (inst inswl value temp temp2)
546 (inst bis temp1 temp2 temp)
547 (inst stq_u temp (- (* ,offset word-bytes)
548 (* index ,scale) ,lowtag) object))))
549 (move value result))))))