1 ;;;; various useful macros for generating MIPS 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.
13 ;;; Handy macro for defining top-level forms that depend on the compile
16 (defmacro expand (expr)
17 (let ((gensym (gensym)))
24 ;;; Instruction-like macros.
26 (defmacro move (dst src &optional (always-emit-code-p nil))
27 "Move SRC into DST (unless they are location= and ALWAYS-EMIT-CODE-P
29 (once-only ((n-dst dst)
31 (if always-emit-code-p
32 `(inst move ,n-dst ,n-src)
33 `(unless (location= ,n-dst ,n-src)
34 (inst move ,n-dst ,n-src)))))
36 (defmacro def-mem-op (op inst shift load)
37 `(defmacro ,op (object base &optional (offset 0) (lowtag 0))
39 (inst ,',inst ,object ,base (- (ash ,offset ,,shift) ,lowtag))
40 ,,@(when load '('(inst nop))))))
42 (def-mem-op loadw lw word-shift t)
43 (def-mem-op storew sw word-shift nil)
45 (defmacro load-symbol (reg symbol)
46 `(inst addu ,reg null-tn (static-symbol-offset ,symbol)))
48 (defmacro load-symbol-value (reg symbol)
51 (+ (static-symbol-offset ',symbol)
52 (ash symbol-value-slot word-shift)
53 (- other-pointer-lowtag)))
56 (defmacro store-symbol-value (reg symbol)
57 `(inst sw ,reg null-tn
58 (+ (static-symbol-offset ',symbol)
59 (ash symbol-value-slot word-shift)
60 (- other-pointer-lowtag))))
62 (defmacro load-type (target source &optional (offset 0))
63 "Loads the type bits of a pointer into target independent of
64 byte-ordering issues."
65 (once-only ((n-target target)
68 (ecase *backend-byte-order*
70 `(inst lbu ,n-target ,n-source ,n-offset ))
72 `(inst lbu ,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 (function lip)
79 "Jump to the lisp function FUNCTION. LIP is an interior-reg temporary."
81 (inst addu ,lip ,function (- (ash simple-fun-code-offset word-shift)
84 (move code-tn ,function)))
86 (defmacro lisp-return (return-pc lip &key (offset 0) (frob-code t))
87 "Return to RETURN-PC. LIP is an interior-reg temporary."
89 (inst addu ,lip ,return-pc
90 (- (* (1+ ,offset) n-word-bytes) other-pointer-lowtag))
93 `(move code-tn ,return-pc)
97 (defmacro emit-return-pc (label)
98 "Emit a return-pc header word. LABEL is the label to use for this return-pc."
100 (align n-lowtag-bits)
102 (inst lra-header-word)))
108 ;;; Load-Stack-TN, Store-Stack-TN -- Interface
110 ;;; Move a stack TN to a register and vice-versa.
111 (defmacro load-stack-tn (reg stack)
114 (let ((offset (tn-offset stack)))
117 (loadw reg cfp-tn offset))))))
119 (defmacro store-stack-tn (stack reg)
120 `(let ((stack ,stack)
122 (let ((offset (tn-offset stack)))
125 (storew reg cfp-tn offset))))))
127 (defmacro maybe-load-stack-tn (reg reg-or-stack)
128 "Move the TN Reg-Or-Stack into Reg if it isn't already there."
129 (once-only ((n-reg reg)
130 (n-stack reg-or-stack))
132 ((any-reg descriptor-reg)
134 ((any-reg descriptor-reg)
135 (move ,n-reg ,n-stack))
137 (loadw ,n-reg cfp-tn (tn-offset ,n-stack))))))))
140 ;;;; Storage allocation:
141 (defmacro with-fixed-allocation ((result-tn flag-tn temp-tn type-code size)
143 "Do stuff to allocate an other-pointer object of fixed Size with a single
144 word header having the specified Type-Code. The result is placed in
145 Result-TN, Flag-Tn must be wired to NL3-OFFSET, and Temp-TN is a non-
146 descriptor temp (which may be randomly used by the body.) The body is
147 placed inside the PSEUDO-ATOMIC, and presumably initializes the object."
148 `(pseudo-atomic (,flag-tn :extra (pad-data-block ,size))
149 (inst or ,result-tn alloc-tn other-pointer-lowtag)
150 (inst li ,temp-tn (logior (ash (1- ,size) n-widetag-bits) ,type-code))
151 (storew ,temp-tn ,result-tn 0 other-pointer-lowtag)
156 ;;;; Three Way Comparison
157 (defun three-way-comparison (x y condition flavor not-p target temp)
161 (inst bne x y target)
162 (inst beq x y target)))
166 (inst sltu temp x y))
168 (inst slt temp x y)))
170 (inst beq temp zero-tn target)
171 (inst bne temp zero-tn target)))
175 (inst sltu temp y x))
177 (inst slt temp y x)))
179 (inst beq temp zero-tn target)
180 (inst bne temp zero-tn target))))
186 (eval-when (compile load eval)
187 (defun emit-error-break (vop kind code values)
188 (let ((vector (gensym)))
191 (note-this-location vop :internal-error)))
193 (with-adjustable-vector (,vector)
194 (write-var-integer (error-number-or-lose ',code) ,vector)
195 ,@(mapcar #'(lambda (tn)
197 (write-var-integer (make-sc-offset (sc-number
202 (inst byte (length ,vector))
203 (dotimes (i (length ,vector))
204 (inst byte (aref ,vector i))))
205 (align word-shift)))))
207 (defmacro error-call (vop error-code &rest values)
208 "Cause an error. ERROR-CODE is the error to cause."
210 (emit-error-break vop error-trap error-code values)))
213 (defmacro cerror-call (vop label error-code &rest values)
214 "Cause a continuable error. If the error is continued, execution resumes at
218 ,@(emit-error-break vop cerror-trap error-code values)))
220 (defmacro generate-error-code (vop error-code &rest values)
221 "Generate-Error-Code Error-code Value*
222 Emit code for an error with the specified Error-Code and context Values."
223 `(assemble (*elsewhere*)
224 (let ((start-lab (gen-label)))
225 (emit-label start-lab)
226 (error-call ,vop ,error-code ,@values)
229 (defmacro generate-cerror-code (vop error-code &rest values)
230 "Generate-CError-Code Error-code Value*
231 Emit code for a continuable error with the specified Error-Code and
232 context Values. If the error is continued, execution resumes after
233 the GENERATE-CERROR-CODE form."
234 (let ((continue (gensym "CONTINUE-LABEL-"))
235 (error (gensym "ERROR-LABEL-")))
236 `(let ((,continue (gen-label)))
237 (emit-label ,continue)
238 (assemble (*elsewhere*)
239 (let ((,error (gen-label)))
241 (cerror-call ,vop ,continue ,error-code ,@values)
245 ;;; PSEUDO-ATOMIC -- Handy macro for making sequences look atomic.
246 (defmacro pseudo-atomic ((flag-tn &key (extra 0)) &rest forms)
248 (aver (= (tn-offset ,flag-tn) nl4-offset))
249 (aver (not (minusp ,extra)))
250 (without-scheduling ()
251 (inst li ,flag-tn ,extra)
252 (inst addu alloc-tn 1))
254 (without-scheduling ()
255 (let ((label (gen-label)))
259 (inst bgez ,flag-tn label)
260 (inst addu alloc-tn (1- ,extra))
262 (emit-label label)))))
266 ;;;; Memory accessor vop generators
268 (deftype load/store-index (scale lowtag min-offset
269 &optional (max-offset min-offset))
270 `(integer ,(- (truncate (+ (ash 1 16)
271 (* min-offset n-word-bytes)
274 ,(truncate (- (+ (1- (ash 1 16)) lowtag)
275 (* max-offset n-word-bytes))
278 (defmacro define-full-reffer (name type offset lowtag scs el-type
283 `((:translate ,translate)))
285 (:args (object :scs (descriptor-reg))
286 (index :scs (any-reg)))
287 (:arg-types ,type tagged-num)
288 (:temporary (:scs (interior-reg)) lip)
289 (:results (value :scs ,scs))
290 (:result-types ,el-type)
292 (inst add lip object index)
293 (inst lw value lip (- (* ,offset n-word-bytes) ,lowtag))
295 (define-vop (,(symbolicate name "-C"))
297 `((:translate ,translate)))
299 (:args (object :scs (descriptor-reg)))
302 (:constant (load/store-index ,n-word-bytes ,(eval lowtag)
304 (:results (value :scs ,scs))
305 (:result-types ,el-type)
307 (inst lw value object (- (* (+ ,offset index) n-word-bytes) ,lowtag))
310 (defmacro define-full-setter (name type offset lowtag scs el-type
315 `((:translate ,translate)))
317 (:args (object :scs (descriptor-reg))
318 (index :scs (any-reg))
319 (value :scs ,scs :target result))
320 (:arg-types ,type tagged-num ,el-type)
321 (:temporary (:scs (interior-reg)) lip)
322 (:results (result :scs ,scs))
323 (:result-types ,el-type)
325 (inst add lip object index)
326 (inst sw value lip (- (* ,offset n-word-bytes) ,lowtag))
327 (move result value)))
328 (define-vop (,(symbolicate name "-C"))
330 `((:translate ,translate)))
332 (:args (object :scs (descriptor-reg))
336 (:constant (load/store-index ,n-word-bytes ,(eval lowtag)
339 (:results (result :scs ,scs))
340 (:result-types ,el-type)
342 (inst sw value object (- (* (+ ,offset index) n-word-bytes) ,lowtag))
343 (move result value)))))
346 (defmacro define-partial-reffer (name type size signed offset lowtag scs
347 el-type &optional translate)
348 (let ((scale (ecase size (:byte 1) (:short 2))))
352 `((:translate ,translate)))
354 (:args (object :scs (descriptor-reg))
355 (index :scs (unsigned-reg)))
356 (:arg-types ,type positive-fixnum)
357 (:results (value :scs ,scs))
358 (:result-types ,el-type)
359 (:temporary (:scs (interior-reg)) lip)
361 (inst addu lip object index)
362 ,@(when (eq size :short)
363 '((inst addu lip index)))
365 (:byte (if signed 'lb 'lbu))
366 (:short (if signed 'lh 'lhu)))
367 value lip (- (* ,offset n-word-bytes) ,lowtag))
369 (define-vop (,(symbolicate name "-C"))
371 `((:translate ,translate)))
373 (:args (object :scs (descriptor-reg)))
376 (:constant (load/store-index ,scale
379 (:results (value :scs ,scs))
380 (:result-types ,el-type)
383 (:byte (if signed 'lb 'lbu))
384 (:short (if signed 'lh 'lhu)))
386 (- (+ (* ,offset n-word-bytes) (* index ,scale)) ,lowtag))
389 (defmacro define-partial-setter (name type size offset lowtag scs el-type
391 (let ((scale (ecase size (:byte 1) (:short 2))))
395 `((:translate ,translate)))
397 (:args (object :scs (descriptor-reg))
398 (index :scs (unsigned-reg))
399 (value :scs ,scs :target result))
400 (:arg-types ,type positive-fixnum ,el-type)
401 (:temporary (:scs (interior-reg)) lip)
402 (:results (result :scs ,scs))
403 (:result-types ,el-type)
405 (inst addu lip object index)
406 ,@(when (eq size :short)
407 '((inst addu lip index)))
408 (inst ,(ecase size (:byte 'sb) (:short 'sh))
409 value lip (- (* ,offset n-word-bytes) ,lowtag))
410 (move result value)))
411 (define-vop (,(symbolicate name "-C"))
413 `((:translate ,translate)))
415 (:args (object :scs (descriptor-reg))
416 (value :scs ,scs :target result))
419 (:constant (load/store-index ,scale
423 (:results (result :scs ,scs))
424 (:result-types ,el-type)
426 (inst ,(ecase size (:byte 'sb) (:short 'sh))
428 (- (* ,offset n-word-bytes) (* index ,scale) ,lowtag))
429 (move result value))))))