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 (location= ,n-dst
,n-src
)
32 (when ,always-emit-code-p
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 (once-only ((reg reg
) (symbol symbol
))
47 `(inst addu
,reg null-tn
(static-symbol-offset ,symbol
))))
49 (defmacro load-symbol-value
(reg symbol
)
52 (+ (static-symbol-offset ',symbol
)
53 (ash symbol-value-slot word-shift
)
54 (- other-pointer-lowtag
)))
57 (defmacro store-symbol-value
(reg symbol
)
58 `(inst sw
,reg null-tn
59 (+ (static-symbol-offset ',symbol
)
60 (ash symbol-value-slot word-shift
)
61 (- other-pointer-lowtag
))))
63 (defmacro load-type
(target source
&optional
(offset 0))
64 "Loads the type bits of a pointer into target independent of
65 byte-ordering issues."
66 (once-only ((n-target target
)
69 (ecase *backend-byte-order
*
71 `(inst lbu
,n-target
,n-source
,n-offset
))
73 `(inst lbu
,n-target
,n-source
(+ ,n-offset
(1- n-word-bytes
)))))))
76 ;;; Macros to handle the fact that we cannot use the machine native call and
77 ;;; return instructions.
79 (defmacro lisp-jump
(function lip
)
80 "Jump to the lisp function FUNCTION. LIP is an interior-reg temporary."
82 (inst addu
,lip
,function
(- (ash simple-fun-code-offset word-shift
)
85 (move code-tn
,function t
)))
87 (defmacro lisp-return
(return-pc lip
&key
(offset 0) (frob-code t
))
88 "Return to RETURN-PC. LIP is an interior-reg temporary."
90 (inst addu
,lip
,return-pc
91 (- (* (1+ ,offset
) n-word-bytes
) other-pointer-lowtag
))
94 `(move code-tn
,return-pc t
)
98 (defmacro emit-return-pc
(label)
99 "Emit a return-pc header word. LABEL is the label to use for this return-pc."
101 (emit-alignment n-lowtag-bits
)
103 (inst lra-header-word
)))
109 ;;; Move a stack TN to a register and vice-versa.
110 (defmacro load-stack-tn
(reg stack
)
113 (let ((offset (tn-offset stack
)))
116 (loadw reg cfp-tn offset
))))))
118 (defmacro store-stack-tn
(stack reg
)
119 `(let ((stack ,stack
)
121 (let ((offset (tn-offset stack
)))
124 (storew reg cfp-tn offset
))))))
126 (defmacro maybe-load-stack-tn
(reg reg-or-stack
)
127 "Move the TN Reg-Or-Stack into Reg if it isn't already there."
128 (once-only ((n-reg reg
)
129 (n-stack reg-or-stack
))
131 ((any-reg descriptor-reg
)
133 ((any-reg descriptor-reg
)
134 (move ,n-reg
,n-stack
))
136 (loadw ,n-reg cfp-tn
(tn-offset ,n-stack
))))))))
139 ;;;; Storage allocation:
140 (defmacro with-fixed-allocation
((result-tn flag-tn temp-tn type-code
141 size dynamic-extent-p
142 &key
(lowtag other-pointer-lowtag
))
144 "Do stuff to allocate an other-pointer object of fixed Size with a single
145 word header having the specified Type-Code. The result is placed in
146 Result-TN, Flag-Tn must be wired to NL4-OFFSET, and Temp-TN is a non-
147 descriptor temp (which may be randomly used by the body.) The body is
148 placed inside the PSEUDO-ATOMIC, and presumably initializes the object."
150 (bug "empty &body in WITH-FIXED-ALLOCATION"))
151 (once-only ((result-tn result-tn
) (flag-tn flag-tn
) (temp-tn temp-tn
)
152 (type-code type-code
) (size size
)
153 (dynamic-extent-p dynamic-extent-p
)
155 `(if ,dynamic-extent-p
156 (pseudo-atomic (,flag-tn
)
158 (inst or
,result-tn csp-tn
,lowtag
)
159 (inst li
,temp-tn
(logior (ash (1- ,size
) n-widetag-bits
) ,type-code
))
160 (inst addu csp-tn
(pad-data-block ,size
))
161 (storew ,temp-tn
,result-tn
0 ,lowtag
)
163 (pseudo-atomic (,flag-tn
:extra
(pad-data-block ,size
))
164 ;; The pseudo-atomic bit in alloc-tn is set. If the lowtag also
165 ;; has a 1 bit in the same position, we're all set. Otherwise,
166 ;; we need to subtract the pseudo-atomic bit.
167 (inst or
,result-tn alloc-tn
,lowtag
)
168 (unless (logbitp 0 ,lowtag
) (inst subu
,result-tn
1))
169 (inst li
,temp-tn
(logior (ash (1- ,size
) n-widetag-bits
) ,type-code
))
170 (storew ,temp-tn
,result-tn
0 ,lowtag
)
173 (defun align-csp (temp)
174 ;; is used for stack allocation of dynamic-extent objects
175 (let ((aligned (gen-label)))
176 (inst and temp csp-tn lowtag-mask
)
177 (inst beq temp aligned
)
179 (inst addu csp-tn n-word-bytes
)
180 (storew zero-tn csp-tn -
1)
181 (emit-label aligned
)))
184 ;;;; Three Way Comparison
185 (defun three-way-comparison (x y condition flavor not-p target temp
)
189 (inst bne x y target
)
190 (inst beq x y target
)))
194 (inst sltu temp x y
))
196 (inst slt temp x y
)))
198 (inst beq temp target
)
199 (inst bne temp target
)))
203 (inst sltu temp y x
))
205 (inst slt temp y x
)))
207 (inst beq temp target
)
208 (inst bne temp target
))))
214 (defun emit-error-break (vop kind code values
)
217 (note-this-location vop
:internal-error
))
220 (encode-internal-error-args values
)
221 (emit-alignment word-shift
)))
223 (defun error-call (vop error-code
&rest values
)
224 "Cause an error. ERROR-CODE is the error to cause."
225 (emit-error-break vop error-trap
(error-number-or-lose error-code
) values
))
228 (defun cerror-call (vop label error-code
&rest values
)
229 "Cause a continuable error. If the error is continued, execution resumes at
232 (without-scheduling ()
234 (emit-error-break vop cerror-trap
(error-number-or-lose error-code
) values
))))
236 (defun generate-error-code (vop error-code
&rest values
)
237 "Generate-Error-Code Error-code Value*
238 Emit code for an error with the specified Error-Code and context Values."
239 (assemble (*elsewhere
*)
240 (let ((start-lab (gen-label)))
241 (emit-label start-lab
)
242 (apply #'error-call vop error-code values
)
245 (defun generate-cerror-code (vop error-code
&rest values
)
246 "Generate-CError-Code Error-code Value*
247 Emit code for a continuable error with the specified Error-Code and
248 context Values. If the error is continued, execution resumes after
249 the GENERATE-CERROR-CODE form."
251 (let ((continue (gen-label)))
252 (emit-label continue
)
253 (assemble (*elsewhere
*)
254 (let ((error (gen-label)))
256 (apply #'cerror-call vop continue error-code values
)
261 ;;; handy macro for making sequences look atomic
262 (defmacro pseudo-atomic
((flag-tn &key
(extra 0)) &rest forms
)
264 (aver (= (tn-offset ,flag-tn
) nl4-offset
))
265 (aver (not (minusp ,extra
)))
266 (without-scheduling ()
267 (inst li
,flag-tn
,extra
)
268 (inst addu alloc-tn
1))
270 (without-scheduling ()
271 (let ((label (gen-label)))
272 (inst bgez
,flag-tn label
)
273 (inst addu alloc-tn
(1- ,extra
))
274 (inst break
0 pending-interrupt-trap
)
275 (emit-label label
)))))
277 ;;;; memory accessor vop generators
279 (deftype load
/store-index
(scale lowtag min-offset
280 &optional
(max-offset min-offset
))
281 `(integer ,(- (truncate (+ (ash 1 16)
282 (* min-offset n-word-bytes
)
285 ,(truncate (- (+ (1- (ash 1 16)) lowtag
)
286 (* max-offset n-word-bytes
))
289 (defmacro define-full-reffer
(name type offset lowtag scs el-type
294 `((:translate
,translate
)))
296 (:args
(object :scs
(descriptor-reg))
297 (index :scs
(any-reg)))
298 (:arg-types
,type tagged-num
)
299 (:temporary
(:scs
(interior-reg)) lip
)
300 (:results
(value :scs
,scs
))
301 (:result-types
,el-type
)
303 (inst addu lip object index
)
304 (loadw value lip
,offset
,lowtag
)))
305 (define-vop (,(symbolicate name
"-C"))
307 `((:translate
,translate
)))
309 (:args
(object :scs
(descriptor-reg)))
312 (:constant
(load/store-index
,n-word-bytes
,(eval lowtag
)
314 (:results
(value :scs
,scs
))
315 (:result-types
,el-type
)
317 (loadw value object
(+ ,offset index
) ,lowtag
)))))
319 (defmacro define-full-setter
(name type offset lowtag scs el-type
324 `((:translate
,translate
)))
326 (:args
(object :scs
(descriptor-reg))
327 (index :scs
(any-reg))
328 (value :scs
,scs
:target result
))
329 (:arg-types
,type tagged-num
,el-type
)
330 (:temporary
(:scs
(interior-reg)) lip
)
331 (:results
(result :scs
,scs
))
332 (:result-types
,el-type
)
334 (inst addu lip object index
)
335 (storew value lip
,offset
,lowtag
)
336 (move result value
)))
337 (define-vop (,(symbolicate name
"-C"))
339 `((:translate
,translate
)))
341 (:args
(object :scs
(descriptor-reg))
345 (:constant
(load/store-index
,n-word-bytes
,(eval lowtag
)
348 (:results
(result :scs
,scs
))
349 (:result-types
,el-type
)
351 (storew value object
(+ ,offset index
) ,lowtag
)
352 (move result value
)))))
355 (defmacro define-partial-reffer
(name type size signed offset lowtag scs
356 el-type
&optional translate
)
357 (let ((scale (ecase size
(:byte
1) (:short
2))))
361 `((:translate
,translate
)))
363 (:args
(object :scs
(descriptor-reg))
364 (index :scs
(unsigned-reg)))
365 (:arg-types
,type positive-fixnum
)
366 (:results
(value :scs
,scs
))
367 (:result-types
,el-type
)
368 (:temporary
(:scs
(interior-reg)) lip
)
370 (inst addu lip object index
)
371 ,@(when (eq size
:short
)
372 '((inst addu lip index
)))
374 (:byte
(if signed
'lb
'lbu
))
375 (:short
(if signed
'lh
'lhu
)))
376 value lip
(- (* ,offset n-word-bytes
) ,lowtag
))
378 (define-vop (,(symbolicate name
"-C"))
380 `((:translate
,translate
)))
382 (:args
(object :scs
(descriptor-reg)))
385 (:constant
(load/store-index
,scale
388 (:results
(value :scs
,scs
))
389 (:result-types
,el-type
)
392 (:byte
(if signed
'lb
'lbu
))
393 (:short
(if signed
'lh
'lhu
)))
395 (- (+ (* ,offset n-word-bytes
) (* index
,scale
)) ,lowtag
))
398 (defmacro define-partial-setter
(name type size offset lowtag scs el-type
400 (let ((scale (ecase size
(:byte
1) (:short
2))))
404 `((:translate
,translate
)))
406 (:args
(object :scs
(descriptor-reg))
407 (index :scs
(unsigned-reg))
408 (value :scs
,scs
:target result
))
409 (:arg-types
,type positive-fixnum
,el-type
)
410 (:temporary
(:scs
(interior-reg)) lip
)
411 (:results
(result :scs
,scs
))
412 (:result-types
,el-type
)
414 (inst addu lip object index
)
415 ,@(when (eq size
:short
)
416 '((inst addu lip index
)))
417 (inst ,(ecase size
(:byte
'sb
) (:short
'sh
))
418 value lip
(- (* ,offset n-word-bytes
) ,lowtag
))
419 (move result value
)))
420 (define-vop (,(symbolicate name
"-C"))
422 `((:translate
,translate
)))
424 (:args
(object :scs
(descriptor-reg))
425 (value :scs
,scs
:target result
))
428 (:constant
(load/store-index
,scale
432 (:results
(result :scs
,scs
))
433 (:result-types
,el-type
)
435 (inst ,(ecase size
(:byte
'sb
) (:short
'sh
))
437 (- (+ (* ,offset n-word-bytes
) (* index
,scale
)) ,lowtag
))
438 (move result value
))))))