source: branches/1.1/ccl/compiler/PPC/ppc-lapmacros.lisp

Last change on this file was 5096, checked in by Gary Byers, 18 years ago

Typo in the (unused) 64-bit/no crf case of UNBOX-BASE-CHAR.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.4 KB
Line 
1;;;-*- Mode: Lisp; Package: CCL -*-
2;;;
3;;; Copyright (C) 1994-2001 Digitool, Inc
4;;; This file is part of OpenMCL.
5;;;
6;;; OpenMCL is licensed under the terms of the Lisp Lesser GNU Public
7;;; License , known as the LLGPL and distributed with OpenMCL as the
8;;; file "LICENSE". The LLGPL consists of a preamble and the LGPL,
9;;; which is distributed with OpenMCL as the file "LGPL". Where these
10;;; conflict, the preamble takes precedence.
11;;;
12;;; OpenMCL is referenced in the preamble as the "LIBRARY."
13;;;
14;;; The LLGPL is also available online at
15;;; http://opensource.franz.com/preamble.html
16
17
18(eval-when (:compile-toplevel :load-toplevel :execute)
19 (require "PPC-LAP"))
20
21
22(defppclapmacro clrrri (&rest args)
23 (target-arch-case
24 (:ppc32 `(clrrwi ,@args))
25 (:ppc64 `(clrrdi ,@args))))
26
27(defppclapmacro clrlri (&rest args)
28 (target-arch-case
29 (:ppc32 `(clrlwi ,@args))
30 (:ppc64 `(clrldi ,@args))))
31
32(defppclapmacro clrlri. (&rest args)
33 (target-arch-case
34 (:ppc32 `(clrlwi. ,@args))
35 (:ppc64 `(clrldi. ,@args))))
36
37(defppclapmacro ldr (&rest args)
38 (target-arch-case
39 (:ppc32 `(lwz ,@args))
40 (:ppc64 `(ld ,@args))))
41
42(defppclapmacro ldrx (&rest args)
43 (target-arch-case
44 (:ppc32 `(lwzx ,@args))
45 (:ppc64 `(ldx ,@args))))
46
47(defppclapmacro ldru (&rest args)
48 (target-arch-case
49 (:ppc32 `(lwzu ,@args))
50 (:ppc64 `(ldu ,@args))))
51
52(defppclapmacro str (&rest args)
53 (target-arch-case
54 (:ppc32 `(stw ,@args))
55 (:ppc64 `(std ,@args))))
56
57(defppclapmacro strx (&rest args)
58 (target-arch-case
59 (:ppc32 `(stwx ,@args))
60 (:ppc64 `(stdx ,@args))))
61
62(defppclapmacro stru (&rest args)
63 (target-arch-case
64 (:ppc32 `(stwu ,@args))
65 (:ppc64 `(stdu ,@args))))
66
67(defppclapmacro strux (&rest args)
68 (target-arch-case
69 (:ppc32 `(stwux ,@args))
70 (:ppc64 `(stdux ,@args))))
71
72(defppclapmacro lrarx (&rest args)
73 (target-arch-case
74 (:ppc32 `(lwarx ,@args))
75 (:ppc64 `(ldarx ,@args))))
76
77(defppclapmacro strcx. (&rest args)
78 (target-arch-case
79 (:ppc32 `(stwcx. ,@args))
80 (:ppc64 `(stdcx. ,@args))))
81
82(defppclapmacro cmpr (&rest args)
83 (target-arch-case
84 (:ppc32 `(cmpw ,@args))
85 (:ppc64 `(cmpd ,@args))))
86
87(defppclapmacro cmpri (&rest args)
88 (target-arch-case
89 (:ppc32 `(cmpwi ,@args))
90 (:ppc64 `(cmpdi ,@args))))
91
92(defppclapmacro cmplr (&rest args)
93 (target-arch-case
94 (:ppc32 `(cmplw ,@args))
95 (:ppc64 `(cmpld ,@args))))
96
97(defppclapmacro cmplri (&rest args)
98 (target-arch-case
99 (:ppc32 `(cmplwi ,@args))
100 (:ppc64 `(cmpldi ,@args))))
101
102(defppclapmacro trlge (&rest args)
103 (target-arch-case
104 (:ppc32 `(twlge ,@args))
105 (:ppc64 `(tdlge ,@args))))
106
107(defppclapmacro trlgei (&rest args)
108 (target-arch-case
109 (:ppc32 `(twlgei ,@args))
110 (:ppc64 `(tdlgei ,@args))))
111
112(defppclapmacro trllt (&rest args)
113 (target-arch-case
114 (:ppc32 `(twllt ,@args))
115 (:ppc64 `(tdllt ,@args))))
116
117(defppclapmacro trllti (&rest args)
118 (target-arch-case
119 (:ppc32 `(twllti ,@args))
120 (:ppc64 `(tdllti ,@args))))
121
122(defppclapmacro trlgti (&rest args)
123 (target-arch-case
124 (:ppc32 `(twlgti ,@args))
125 (:ppc64 `(tdlgti ,@args))))
126
127(defppclapmacro trlti (&rest args)
128 (target-arch-case
129 (:ppc32 `(twlti ,@args))
130 (:ppc64 `(tdlti ,@args))))
131
132(defppclapmacro trlle (&rest args)
133 (target-arch-case
134 (:ppc32 `(twlle ,@args))
135 (:ppc64 `(tdlle ,@args))))
136
137(defppclapmacro treqi (&rest args)
138 (target-arch-case
139 (:ppc32 `(tweqi ,@args))
140 (:ppc64 `(tdeqi ,@args))))
141
142(defppclapmacro trnei (&rest args)
143 (target-arch-case
144 (:ppc32 `(twnei ,@args))
145 (:ppc64 `(tdnei ,@args))))
146
147(defppclapmacro trgti (&rest args)
148 (target-arch-case
149 (:ppc32 `(twgti ,@args))
150 (:ppc64 `(tdgti ,@args))))
151
152
153(defppclapmacro srari (&rest args)
154 (target-arch-case
155 (:ppc32 `(srawi ,@args))
156 (:ppc64 `(sradi ,@args))))
157
158(defppclapmacro srar (&rest args)
159 (target-arch-case
160 (:ppc32 `(sraw ,@args))
161 (:ppc64 `(srad ,@args))))
162
163(defppclapmacro slr (&rest args)
164 (target-arch-case
165 (:ppc32 `(slw ,@args))
166 (:ppc64 `(sld ,@args))))
167
168(defppclapmacro srri (&rest args)
169 (target-arch-case
170 (:ppc32 `(srwi ,@args))
171 (:ppc64 `(srdi ,@args))))
172
173(defppclapmacro slri (&rest args)
174 (target-arch-case
175 (:ppc32 `(slwi ,@args))
176 (:ppc64 `(sldi ,@args))))
177
178(defppclapmacro srr (&rest args)
179 (target-arch-case
180 (:ppc32 `(srw ,@args))
181 (:ppc64 `(srd ,@args))))
182
183(defppclapmacro bkpt ()
184 `(tweq rzero rzero))
185
186(defppclapmacro dbg (&optional save-lr?)
187 (if save-lr?
188 `(progn
189 (mflr loc-pc)
190 (str imm0 -40 sp) ; better than clobbering imm0
191 (bla .SPbreakpoint)
192 (ldr imm0 -40 sp)
193 (mtlr loc-pc))
194 `(bla .SPbreakpoint)))
195
196(defppclapmacro lwi (dest n)
197 (setq n (logand n #xffffffff))
198 (let* ((mask #xffff8000)
199 (masked (logand n mask))
200 (high (ash n -16))
201 (low (logand #xffff n)))
202 (if (or (= 0 masked) (= mask masked))
203 `(li ,dest ,low)
204 (if (= low 0)
205 `(lis ,dest ,high)
206 `(progn
207 (lis ,dest ,high)
208 (ori ,dest ,dest ,low))))))
209
210(defppclapmacro set-nargs (n)
211 (check-type n (unsigned-byte 13))
212 `(li nargs ',n))
213
214(defppclapmacro check-nargs (min &optional (max min))
215 (if (eq max min)
216 `(trnei nargs ',min)
217 (if (null max)
218 (unless (= min 0)
219 `(trllti nargs ',min))
220 (if (= min 0)
221 `(trlgti nargs ',max)
222 `(progn
223 (trllti nargs ',min)
224 (trlgti nargs ',max))))))
225
226;; Event-polling involves checking to see if the value of the current
227;; thread's interrupt-level is > 0. For now, use nargs; this may
228;; change to "any register BUT nargs". (Note that most number-of-args
229;; traps use unsigned comparisons.)
230(defppclapmacro event-poll ()
231 (target-arch-case
232 (:ppc32
233 '(progn
234 (lwz nargs ppc32::tcr.tlb-pointer ppc32::rcontext)
235 (lwz nargs ppc32::interrupt-level-binding-index nargs)
236 (twgti nargs 0)))
237 (:ppc64
238 '(progn
239 (ld nargs ppc64::tcr.tlb-pointer ppc64::rcontext)
240 (ld nargs ppc64::interrupt-level-binding-index nargs)
241 (tdgti nargs 0)))))
242
243
244;;; There's no "else"; learn to say "(progn ...)".
245;;; Note also that the condition is a CR bit specification (or a "negated" one).
246;;; Whatever affected that bit (hopefully) happened earlier in the pipeline.
247(defppclapmacro if (test then &optional (else nil else-p))
248 (multiple-value-bind (bitform negated) (ppc-lap-parse-test test)
249 (let* ((false-label (gensym)))
250 (if (not else-p)
251 `(progn
252 (,(if negated 'bt 'bf) ,bitform ,false-label)
253 ,then
254 ,false-label)
255 (let* ((cont-label (gensym)))
256 `(progn
257 (,(if negated 'bt 'bf) ,bitform ,false-label)
258 ,then
259 (b ,cont-label)
260 ,false-label
261 ,else
262 ,cont-label))))))
263
264(defppclapmacro save-pc ()
265 `(mflr loc-pc))
266
267;;; This needs to be done if we aren't a leaf function (e.g., if we
268;;; clobber our return address or need to reference any constants. Note
269;;; that it's not atomic wrt a preemptive scheduler, but we need to
270;;; pretend that it will be.) The VSP to be saved is the value of the
271;;; VSP before any of this function's arguments were vpushed by its
272;;; caller; that's not the same as the VSP register if any non-register
273;;; arguments were received, but is usually easy to compute.
274
275(defppclapmacro save-lisp-context (&optional (vsp 'vsp) (save-pc t))
276 (target-arch-case
277 (:ppc32
278 `(progn
279 ,@(if save-pc
280 '((save-pc)))
281 (stwu sp (- ppc32::lisp-frame.size) sp)
282 (stw fn ppc32::lisp-frame.savefn sp)
283 (stw loc-pc ppc32::lisp-frame.savelr sp)
284 (stw ,vsp ppc32::lisp-frame.savevsp sp)
285 (mr fn nfn)))
286 (:ppc64
287 `(progn
288 ,@(if save-pc
289 '((save-pc)))
290 (stdu sp (- ppc64::lisp-frame.size) sp)
291 (std fn ppc64::lisp-frame.savefn sp)
292 (std loc-pc ppc64::lisp-frame.savelr sp)
293 (std ,vsp ppc64::lisp-frame.savevsp sp)
294 (mr fn nfn)))))
295
296;;; There are a few cases to deal with when restoring: whether or not
297;;; to restore the vsp, whether we need to saved LR back in the LR or
298;;; whether it only needs to get as far as loc-pc, etc. This fully
299;;; restores everything (letting the caller specify some register
300;;; other than the VSP, if that's useful.) Note that, since FN gets
301;;; restored, it's no longer possible to use it to address the current
302;;; function's constants.
303(defppclapmacro restore-full-lisp-context (&optional (vsp 'vsp))
304 (target-arch-case
305 (:ppc32
306 `(progn
307 (lwz loc-pc ppc32::lisp-frame.savelr sp)
308 (lwz ,vsp ppc32::lisp-frame.savevsp sp)
309 (mtlr loc-pc)
310 (lwz fn ppc32::lisp-frame.savefn sp)
311 (la sp ppc32::lisp-frame.size sp)))
312 (:ppc64
313 `(progn
314 (ld loc-pc ppc64::lisp-frame.savelr sp)
315 (ld ,vsp ppc64::lisp-frame.savevsp sp)
316 (mtlr loc-pc)
317 (ld fn ppc64::lisp-frame.savefn sp)
318 (la sp ppc64::lisp-frame.size sp)))))
319
320(defppclapmacro restore-pc ()
321 `(mtlr loc-pc))
322
323(defppclapmacro push (src stack)
324 `(stru ,src ,(- (arch::target-lisp-node-size (backend-target-arch *target-backend*))) ,stack))
325
326(defppclapmacro vpush (src)
327 `(push ,src vsp))
328
329;;; You typically don't want to do this to pop a single register (it's better to
330;;; do a sequence of loads, and then adjust the stack pointer.)
331
332(defppclapmacro pop (dest stack)
333 `(progn
334 (ldr ,dest 0 ,stack)
335 (la ,stack ,(arch::target-lisp-node-size (backend-target-arch *target-backend*)) ,stack)))
336
337(defppclapmacro vpop (dest)
338 `(pop ,dest vsp))
339
340(defppclapmacro %cdr (dest node)
341 (target-arch-case
342 (:ppc32 `(lwz ,dest ppc32::cons.cdr ,node))
343 (:ppc64 `(ld ,dest ppc64::cons.cdr ,node))))
344
345(defppclapmacro %car (dest node)
346 (target-arch-case
347 (:ppc32 `(lwz ,dest ppc32::cons.car ,node))
348 (:ppc64 `(ld ,dest ppc64::cons.car ,node))))
349
350(defppclapmacro extract-lisptag (dest node)
351 (let* ((tb *target-backend*))
352 `(clrlri ,dest ,node (- ,(arch::target-nbits-in-word (backend-target-arch tb))
353 ,(arch::target-nlisptagbits (backend-target-arch tb))))))
354
355(defppclapmacro extract-fulltag (dest node)
356 (let* ((tb *target-backend*))
357 `(clrlri ,dest ,node (- ,(arch::target-nbits-in-word (backend-target-arch tb))
358 ,(arch::target-ntagbits (backend-target-arch tb))))))
359
360(defppclapmacro extract-lowtag (dest node)
361 (target-arch-case
362 (:ppc32
363 (error "EXTRACT-LOWTAG lapmacro makes no sense on PPC32."))
364 (:ppc64
365 `(clrldi ,dest ,node (- 64 ppc64::nlowtagbits)))))
366
367
368(defppclapmacro extract-subtag (dest node)
369 (target-arch-case
370 (:ppc32
371 `(lbz ,dest ppc32::misc-subtag-offset ,node))
372 (:ppc64
373 `(lbz ,dest ppc64::misc-subtag-offset ,node))))
374
375(defppclapmacro extract-typecode (dest node &optional (crf :cr0))
376 (target-arch-case
377 (:ppc32
378 `(progn
379 (extract-lisptag ,dest ,node)
380 (cmpwi ,crf ,dest ppc32::tag-misc)
381 (if (,crf :eq)
382 (extract-subtag ,dest ,node))))
383 (:ppc64
384 `(progn
385 (extract-fulltag ,dest ,node)
386 (cmpdi ,crf ,dest ppc64::fulltag-misc)
387 (extract-lisptag ,dest ,dest)
388 (if (,crf :eq)
389 (extract-subtag ,dest ,node))))))
390
391(defppclapmacro trap-unless-lisptag= (node tag &optional (immreg ppc::imm0))
392 `(progn
393 (extract-lisptag ,immreg ,node)
394 (trnei ,immreg ,tag)))
395
396(defppclapmacro trap-unless-fulltag= (node tag &optional (immreg ppc::imm0))
397 `(progn
398 (extract-fulltag ,immreg ,node)
399 (trnei ,immreg ,tag)))
400
401
402(defppclapmacro trap-unless-typecode= (node tag &optional (immreg ppc::imm0) (crf :cr0))
403 `(progn
404 (extract-typecode ,immreg ,node ,crf)
405 (trnei ,immreg ,tag)))
406
407
408(defppclapmacro load-constant (dest constant)
409 `(ldr ,dest ',constant fn))
410
411;;; This is about as hard on the pipeline as anything I can think of.
412(defppclapmacro call-symbol (function-name)
413 (target-arch-case
414 (:ppc32
415 `(progn
416 (load-constant fname ,function-name)
417 (lwz nfn ppc32::symbol.fcell fname)
418 (lwz loc-pc ppc32::misc-data-offset nfn)
419 (mtctr loc-pc)
420 (bctrl)))
421 (:ppc64
422 `(progn
423 (load-constant fname ,function-name)
424 (ld nfn ppc64::symbol.fcell fname)
425 (ld loc-pc ppc64::misc-data-offset nfn)
426 (mtctr loc-pc)
427 (bctrl)))))
428
429(defppclapmacro sp-call-symbol (function-name)
430 `(progn
431 (load-constant fname ,function-name)
432 (bla .SPjmpsym)))
433
434(defppclapmacro getvheader (dest src)
435 (target-arch-case
436 (:ppc32
437 `(lwz ,dest ppc32::misc-header-offset ,src))
438 (:ppc64
439 `(ld ,dest ppc64::misc-header-offset ,src))))
440
441;;; "Size" is unboxed element-count.
442(defppclapmacro header-size (dest vheader)
443 (target-arch-case
444 (:ppc32
445 `(srwi ,dest ,vheader ppc32::num-subtag-bits))
446 (:ppc64
447 `(srdi ,dest ,vheader ppc64::num-subtag-bits))))
448
449
450;;; "Length" is fixnum element-count.
451(defppclapmacro header-length (dest vheader)
452 (target-arch-case
453 (:ppc32
454 `(rlwinm ,dest
455 ,vheader
456 (- ppc32::nbits-in-word (- ppc32::num-subtag-bits ppc32::nfixnumtagbits))
457 (- ppc32::num-subtag-bits ppc32::nfixnumtagbits)
458 (- ppc32::least-significant-bit ppc32::nfixnumtagbits)))
459 (:ppc64
460 `(progn
461 (rldicr ,dest
462 ,vheader
463 (- 64 (- ppc64::num-subtag-bits ppc64::fixnumshift))
464 (- 63 ppc64::fixnumshift))
465 (clrldi ,dest ,dest (- ppc64::num-subtag-bits ppc64::fixnumshift))))))
466
467
468(defppclapmacro header-subtag[fixnum] (dest vheader)
469 (target-arch-case
470 (:ppc32
471 `(rlwinm ,dest
472 ,vheader
473 ppc32::fixnumshift
474 (- ppc32::nbits-in-word (+ ppc32::num-subtag-bits ppc32::nfixnumtagbits))
475 (- ppc32::least-significant-bit ppc32::nfixnumtagbits)))
476 (:ppc64
477 `(clrlsldi ,dest
478 ,vheader (- ppc64::nbits-in-word ppc64::num-subtag-bits)
479 ppc64::fixnumshift))))
480
481
482(defppclapmacro vector-size (dest v vheader)
483 `(progn
484 (getvheader ,vheader ,v)
485 (header-size ,dest ,vheader)))
486
487(defppclapmacro vector-length (dest v vheader)
488 `(progn
489 (getvheader ,vheader ,v)
490 (header-length ,dest ,vheader)))
491
492
493;;; Reference a 32-bit miscobj entry at a variable index.
494;;; Make the caller explicitly designate a scratch register
495;;; to use for the scaled index.
496
497(defppclapmacro vref32 (dest miscobj index scaled-idx)
498 `(progn
499 (la ,scaled-idx ppc32::misc-data-offset ,index)
500 (lwzx ,dest ,miscobj ,scaled-idx)))
501
502;; The simple (no-memoization) case.
503(defppclapmacro vset32 (src miscobj index scaled-idx)
504 `(progn
505 (la ,scaled-idx ppc32::misc-data-offset ,index)
506 (stwx ,src ,miscobj ,scaled-idx)))
507
508(defppclapmacro extract-lowbyte (dest src)
509 (target-arch-case
510 (:ppc32 `(clrlwi ,dest ,src (- 32 8)))
511 (:ppc64 `(clrldi ,dest ,src (- 64 8)))))
512
513(defppclapmacro unbox-fixnum (dest src)
514 (target-arch-case
515 (:ppc32
516 `(srawi ,dest ,src ppc32::fixnumshift))
517 (:ppc64
518 `(sradi ,dest ,src ppc64::fixnumshift))))
519
520(defppclapmacro box-fixnum (dest src)
521 (target-arch-case
522 (:ppc32
523 `(slwi ,dest ,src ppc32::fixnumshift))
524 (:ppc64
525 `(sldi ,dest ,src ppc64::fixnumshift))))
526
527
528
529;;; If crf is specified, type checks src
530(defppclapmacro unbox-base-char (dest src &optional crf)
531 (if (null crf)
532 (target-arch-case
533 (:ppc32 `(srwi ,dest ,src ppc32::charcode-shift))
534 (:ppc64 `(srdi ,dest ,src ppc64::charcode-shift)))
535 (let ((label (gensym)))
536 (target-arch-case
537 (:ppc32 `(progn
538 (clrlwi ,dest ,src (- ppc32::nbits-in-word ppc32::charcode-shift))
539 (cmpwi ,crf ,dest ppc32::subtag-character)
540 (srwi ,dest ,src ppc32::charcode-shift)
541 (beq+ ,crf ,label)
542 (uuo_interr arch::error-object-not-base-char ,src)
543 ,label))
544 (:ppc64
545 `(progn
546 (clrldi ,dest ,src (- ppc64::nbits-in-word ppc64::num-subtag-bits))
547 (cmpdi ,crf ,dest ppc64::subtag-character)
548 (srdi ,dest ,src ppc64::charcode-shift)
549 (beq+ ,crf ,label)
550 (uuo_interr arch::error-object-not-base-char ,src)
551 ,label))))))
552
553
554
555
556(defppclapmacro ref-global (reg sym)
557 (target-arch-case
558 (:ppc32
559 (let* ((offset (ppc32::%kernel-global sym)))
560 `(lwz ,reg (+ ,offset ppc32::nil-value) 0)))
561 (:ppc64
562 (let* ((offset (ppc64::%kernel-global sym)))
563 `(ld ,reg (+ ,offset ppc64::nil-value) 0)))))
564
565(defppclapmacro set-global (reg sym)
566 (target-arch-case
567 (:ppc32
568 (let* ((offset (ppc32::%kernel-global sym)))
569 `(stw ,reg (+ ,offset ppc32::nil-value) 0)))
570 (:ppc64
571 (let* ((offset (ppc64::%kernel-global sym)))
572 `(std ,reg (+ ,offset ppc64::nil-value) 0)))))
573
574;;; Set "dest" to those bits in "src" that are other than those that
575;;; would be set if "src" is a fixnum and of type (unsigned-byte
576;;; "width"). If no bits are set in "dest", then "src" is indeed of
577;;; type (unsigned-byte "width"). Set (:CR0 :EQ) according to the
578;;; result.
579(defppclapmacro extract-unsigned-byte-bits. (dest src width)
580 (target-arch-case
581 (:ppc32
582 `(rlwinm. ,dest ,src 0 (- 32 ppc32::fixnumshift) (- 31 (+ ,width ppc32::fixnumshift))))
583 (:ppc64
584 `(rldicr. ,dest ,src (- 64 ppc64::fixnumshift) (- 63 ,width)))))
585
586
587
588;;; You generally don't want to have to say "mfcr": it crosses functional
589;;; units and forces synchronization (all preceding insns must complete,
590;;; no subsequent insns may start.)
591;;; There are often algebraic ways of computing ppc32::t-offset:
592
593;;; Src has all but the least significant bit clear. Map low bit to T/NIL.
594(defppclapmacro bit0->boolean (dest src temp)
595 (target-arch-case
596 (:ppc32
597 `(progn
598 (rlwimi ,temp ,src 4 27 27)
599 (addi ,dest ,temp ppc32::nil-value)))
600 (:ppc64
601 `(progn
602 (mulli ,temp ,src ppc64::t-offset) ; temp = ppc64::t-offset, or 0
603 (addi ,dest ,temp ppc64::nil-value))))) ; dest = (src == 1), lisp-wise
604
605(defppclapmacro eq0->boolean (dest src temp)
606 (target-arch-case
607 (:ppc32
608 `(progn
609 (cntlzw ,temp ,src) ; 32 leading zeros if (src == 0)
610 (srwi ,temp ,temp 5) ; temp = (src == 0), C-wise
611 (bit0->boolean ,dest ,temp ,temp)))
612 (:ppc64
613 `(progn
614 (cntlzd ,temp ,src) ; 64 leading zeros if (src == 0)
615 (srdi ,temp ,temp 6) ; temp = (src == 0), C-wise
616 (bit0->boolean ,dest ,temp ,temp)))))
617
618(defppclapmacro eq->boolean (dest rx ry temp)
619 `(progn
620 (sub ,temp ,rx ,ry)
621 (eq0->boolean ,dest ,temp ,temp)))
622
623
624(defppclapmacro repeat (n inst)
625 (let* ((insts ()))
626 (dotimes (i n `(progn ,@(nreverse insts)))
627 (push inst insts))))
628
629(defppclapmacro get-single-float (dest node)
630 (target-arch-case
631 (:ppc32
632 `(lfs ,dest ppc32::single-float.value ,node))
633 (:ppc64
634 `(progn
635 (std ,node ppc64::tcr.single-float-convert ppc64::rcontext)
636 (lfs ,dest ppc64::tcr.single-float-convert ppc64::rcontext)))))
637
638(defppclapmacro get-double-float (dest node)
639 (target-arch-case
640 (:ppc32
641 `(lfd ,dest ppc32::double-float.value ,node))
642 (:ppc64
643 `(lfd ,dest ppc64::double-float.value ,node))))
644
645
646(defppclapmacro put-single-float (src node)
647 (target-arch-case
648 (:ppc32
649 `(stfs ,src ppc32::single-float.value ,node))
650 (:ppc64
651 `(progn
652 (stfs ,src ppc64::tcr.single-float-convert ppc64::rcontext)
653 (ld ,node ppc64::tcr.single-float-convert ppc64::rcontext)))))
654
655(defppclapmacro put-double-float (src node)
656 (target-arch-case
657 (:ppc32
658 `(stfd ,src ppc32::double-float.value ,node))
659 (:ppc64
660 `(stfd ,src ppc64::double-float.value ,node))))
661
662(defppclapmacro clear-fpu-exceptions ()
663 `(mtfsf #xfc #.ppc::fp-zero))
664
665
666
667;;; from ppc-bignum.lisp
668(defppclapmacro digit-h (dest src)
669 (target-arch-case
670 (:ppc32
671 `(rlwinm ,dest ,src (+ 16 ppc32::fixnumshift) (- 16 ppc32::fixnumshift) (- 31 ppc32::fixnumshift)))
672 (:ppc64
673 (error "DIGIT-H on PPC64 ?"))))
674
675;;; from ppc-bignum.lisp
676(defppclapmacro digit-l (dest src)
677 (target-arch-case
678 (:ppc32
679 `(clrlslwi ,dest ,src 16 ppc32::fixnumshift))
680 (:ppc64
681 (error "DIGIT-L on PPC64 ?"))))
682
683;;; from ppc-bignum.lisp
684(defppclapmacro compose-digit (dest high low)
685 (target-arch-case
686 (:ppc32
687 `(progn
688 (rlwinm ,dest ,low (- ppc32::nbits-in-word ppc32::fixnumshift) 16 31)
689 (rlwimi ,dest ,high (- 16 ppc32::fixnumshift) 0 15)))
690 (:ppc64
691 (error "COMPOSE-DIGIT on PPC64 ?"))))
692
693(defppclapmacro macptr-ptr (dest macptr)
694 (target-arch-case
695 (:ppc32
696 `(lwz ,dest ppc32::macptr.address ,macptr))
697 (:ppc64
698 `(ld ,dest ppc64::macptr.address ,macptr))))
699
700(defppclapmacro svref (dest index vector)
701 (target-arch-case
702 (:ppc32
703 `(lwz ,dest (+ (* 4 ,index) ppc32::misc-data-offset) ,vector))
704 (:ppc64
705 `(ld ,dest (+ (* 8 ,index) ppc64::misc-data-offset) ,vector))))
706
707;;; This evals its args in the wrong order.
708;;; Can't imagine any code will care.
709(defppclapmacro svset (new-value index vector)
710 (target-arch-case
711 (:ppc32
712 `(stw ,new-value (+ (* 4 ,index) ppc32::misc-data-offset) ,vector))
713 (:ppc64
714 `(std ,new-value (+ (* 8 ,index) ppc64::misc-data-offset) ,vector))))
715
716(defppclapmacro vpush-argregs ()
717 (let* ((none (gensym))
718 (two (gensym))
719 (one (gensym)))
720 `(progn
721 (cmpri cr1 nargs '2)
722 (cmpri cr0 nargs 0)
723 (beq cr1 ,two)
724 (beq cr0 ,none)
725 (blt cr1 ,one)
726 (vpush arg_x)
727 ,two
728 (vpush arg_y)
729 ,one
730 (vpush arg_z)
731 ,none)))
732
733
734
735
736;;; Saving and restoring AltiVec registers.
737
738;;; Note that under the EABI (to which PPCLinux conforms), the OS
739;;; doesn't attach any special significance to the value of the VRSAVE
740;;; register (spr 256). Under some other ABIs, VRSAVE is a bitmask
741;;; which indicates which vector registers are live at context switch
742;;; time. These macros contain code to maintain VRSAVE when the
743;;; variable *ALTIVEC-LAPMACROS-MAINTAIN-VRSAVE-P* is true at
744;;; macroexpand time; that variable is initialized to true if and only
745;;; if :EABI-TARGET is not on *FEATURES*. Making this behavior
746;;; optional is supposed to help make code which uses these macros
747;;; easier to port to other platforms.
748
749;;; From what I can tell, a function that takes incoming arguments in
750;;; vector registers (vr2 ... vr13) (and doesn't use any other vector
751;;; registers) doesn't need to assert that it uses any vector
752;;; registers (even on platforms that maintain VRSAVE.) A function
753;;; that uses vector registers that were not incoming arguments has to
754;;; assert that it uses those registers on platforms that maintain
755;;; VRSAVE. On all platforms, a function that uses any non-volatile
756;;; vector registers (vr20 ... vr31) has to assert that it uses these
757;;; registers and save and restore the caller's value of these registers
758;;; around that usage.
759
760(defparameter *altivec-lapmacros-maintain-vrsave-p*
761 #-eabi-target t
762 #+eabi-target nil
763 "Control the expansion of certain lap macros. Initialized to NIL on
764LinuxPPC; initialized to T on platforms (such as MacOS X/Darwin) that
765require that the VRSAVE SPR contain a bitmask of active vector registers
766at all times.")
767
768(defun %vr-register-mask (reglist)
769 (let* ((mask 0))
770 (dolist (reg reglist mask)
771 (let* ((regval (ppc-vector-register-name-or-expression reg)))
772 (unless (typep regval '(mod 32))
773 (error "Bad AltiVec register - ~s" reg))
774 (setq mask (logior mask (ash #x80000000 (- regval))))))))
775
776
777
778;;; Build a frame on the temp stack large enough to hold N 128-bit vector
779;;; registers and the saved value of the VRSAVE spr. That frame will look
780;;; like:
781;;; #x??????I0 backpointer to previous tstack frame
782;;; #x??????I4 non-zero marker: frame doesn't contain tagged lisp data
783;;; #x??????I8 saved VRSAVE
784;;; #x??????IC pad word for alignment
785;;; #x??????J0 first saved vector register
786;;; #x??????K0 second saved vector register
787;;; ...
788;;; #x??????X0 last saved vector register
789;;; #x??????Y0 (possibly) 8 bytes wasted for alignment.
790;;; #x???????? UNKNOWN; not necessarily the previous tstack frame
791;;;
792;;; Use the specified immediate register to build the frame.
793;;; Save the caller's VRSAVE in the frame.
794
795(defppclapmacro %build-vrsave-frame (n tempreg)
796 (if (or (> n 0) *altivec-lapmacros-maintain-vrsave-p*)
797 (if (zerop n)
798 ;; Just make room for vrsave; no need to align to 16-byte boundary.
799 `(progn
800 (stwu tsp -16 tsp)
801 (stw tsp 4 tsp))
802 `(progn
803 (la ,tempreg ,(- (ash (1+ n) 4)) ppc::tsp)
804 (clrrwi ,tempreg ,tempreg 4) ; align to 16-byte boundary
805 (sub ,tempreg ,tempreg ppc32::tsp) ; calculate (aligned) frame size.
806 (stwux ppc::tsp ppc::tsp ,tempreg)
807 (stw ppc::tsp 4 ppc::tsp))) ; non-zero: non-lisp
808 `(progn)))
809
810;;; Save the current value of the VRSAVE spr in the newly-created
811;;; tstack frame.
812
813(defppclapmacro %save-vrsave (tempreg)
814 (if *altivec-lapmacros-maintain-vrsave-p*
815 `(progn
816 (mfspr ,tempreg 256) ; SPR 256 = vrsave
817 (stw ,tempreg 8 tsp))
818 `(progn)))
819
820
821
822;;; When this is expanded, "tempreg" should contain the caller's vrsave.
823(defppclapmacro %update-vrsave (tempreg mask)
824 (let* ((mask-high (ldb (byte 16 16) mask))
825 (mask-low (ldb (byte 16 0) mask)))
826 `(progn
827 ,@(unless (zerop mask-high) `((oris ,tempreg ,tempreg ,mask-high)))
828 ,@(unless (zerop mask-low) `((ori ,tempreg ,tempreg ,mask-low)))
829 (mtspr 256 ,tempreg))))
830
831;;; Save each of the vector regs in "nvrs" into the current tstack
832;;; frame, starting at offset 16
833(defppclapmacro %save-vector-regs (nvrs tempreg)
834 (let* ((insts ()))
835 (do* ((offset 16 (+ 16 offset))
836 (regs nvrs (cdr regs)))
837 ((null regs) `(progn ,@(nreverse insts)))
838 (declare (fixnum offset))
839 (push `(la ,tempreg ,offset ppc::tsp) insts)
840 (push `(stvx ,(car regs) ppc::rzero ,tempreg) insts))))
841
842
843;;; Pretty much the same idea, only we restore VRSAVE first and
844;;; discard the tstack frame after we've reloaded the vector regs.
845(defppclapmacro %restore-vector-regs (nvrs tempreg)
846 (let* ((loads ()))
847 (do* ((offset 16 (+ 16 offset))
848 (regs nvrs (cdr regs)))
849 ((null regs) `(progn
850 ,@ (when *altivec-lapmacros-maintain-vrsave-p*
851 `((progn
852 (lwz ,tempreg 8 ppc::tsp)
853 (mtspr 256 ,tempreg))))
854 ,@(nreverse loads)
855 (lwz ppc::tsp 0 ppc::tsp)))
856 (declare (fixnum offset))
857 (push `(la ,tempreg ,offset ppc::tsp) loads)
858 (push `(lvx ,(car regs) ppc::rzero ,tempreg) loads))))
859
860
861(defun %extract-non-volatile-vector-registers (vector-reg-list)
862 (let* ((nvrs ()))
863 (dolist (reg vector-reg-list (nreverse nvrs))
864 (let* ((regval (ppc-vector-register-name-or-expression reg)))
865 (unless (typep regval '(mod 32))
866 (error "Bad AltiVec register - ~s" reg))
867 (when (>= regval 20)
868 (pushnew regval nvrs))))))
869
870
871;;; One could imagine something more elaborate:
872;;; 1) Binding a global bitmask that represents the assembly-time notion
873;;; of VRSAVE's contents; #'ppc-vector-register-name-or-expression
874;;; could then warn if a vector register wasn't marked as active.
875;;; Maybe a good idea, but PPC-LAP would have to bind that special
876;;; variable to 0 to make things reentrant.
877;;; 2) Binding a user-specified variable to the list of NVRs that need
878;;; to be restored, so that it'd be more convenient to insert one's
879;;; own calls to %RESTORE-VECTOR-REGS at appropriate points.
880;;; Ad infinitum. As is, this allows one to execute a "flat" body of code
881;;; that's bracketed by the stuff needed to keep VRSAVE in sync and
882;;; to save and restore any non-volatile vector registers specified.
883;;; That body of code is "flat" in the sense that it doesn't return,
884;;; tail-call, establish a catch or unwind-protect frame, etc.
885;;; It -can- contain lisp or foreign function calls.
886
887(defppclapmacro %with-altivec-registers ((&key (immreg 'ppc::imm0)) reglist &body body)
888 (let* ((mask (%vr-register-mask reglist))
889 (nvrs (%extract-non-volatile-vector-registers reglist))
890 (num-nvrs (length nvrs)))
891 (if (or *altivec-lapmacros-maintain-vrsave-p* nvrs)
892 `(progn
893 (%build-vrsave-frame ,num-nvrs ,immreg)
894 (%save-vrsave ,immreg)
895 ,@ (if *altivec-lapmacros-maintain-vrsave-p*
896 `((%update-vrsave ,immreg ,mask)))
897 (%save-vector-regs ,nvrs ,immreg)
898 (progn ,@body)
899 (%restore-vector-regs ,nvrs ,immreg))
900 `(progn ,@body))))
901
902
903(defppclapmacro with-altivec-registers (reglist &body body)
904 "Specify the set of AltiVec registers used in body. If
905*altivec-lapmacros-maintain-vrsave-p* is true when the macro is expanded,
906generates code to save the VRSAVE SPR and updates VRSAVE to incude a
907bitmask generated from the specified register list. Generates code which
908saves any non-volatile vector registers which appear in the register list,
909executes body, and restores the saved non-volatile vector registers (and,
910if *altivec-lapmacros-maintain-vrsave-p* is true, restores VRSAVE as well.
911Uses the IMM0 register (r3) as a temporary."
912 `(%with-altivec-registers () ,reglist ,@body))
913
914
915;;; Create an aligned buffer on the temp stack, large enough for N vector
916;;; registers. Make base be a pointer to this buffer (base can be
917;;; any available GPR, since the buffer will be fixnum-tagged.) N should
918;;; be a constant.
919;;; The intent here is that the register 'base' can be used in subsequent
920;;; stvx/lvx instructions. Any vector registers involved in such instructions
921;;; must have their corresponding bits saved in VRSAVE on platforms where
922;;; that matters.
923
924(defppclapmacro allocate-vector-buffer (base n)
925 `(progn
926 (stwux tsp (- (ash (1+ ,n) 4))) ; allocate a frame on temp stack
927 (stw tsp 4 tsp) ; temp frame contains immediate data
928 (la ,base (+ 8 8) tsp) ; skip header, round up
929 (clrrwi ,base ,base 4))) ; align (round down)
930
931;;; Execute the specified body of code; on entry to that body, BASE
932;;; will point to the lowest address of a vector-aligned buffer with
933;;; room for N vector registers. On exit, the buffer will be
934;;; deallocated. The body should preserve the value of BASE as long
935;;; as it needs to reference the buffer.
936
937(defppclapmacro with-vector-buffer (base n &body body)
938 "Generate code which allocates a 16-byte aligned buffer large enough
939to contain N vector registers; the GPR base points to the lowest address
940of this buffer. After processing body, the buffer will be deallocated.
941The body should preserve the value of base as long as it needs to
942reference the buffer. It's intended that base be used as a base register
943in stvx and lvx instructions within the body."
944 `(progn
945 (allocate-vector-buffer ,base ,n)
946 (progn
947 (progn ,@body)
948 (unlink tsp))))
949
950#|
951
952;;; This is just intended to test the macros; I can't test whether or not the code works.
953
954(defppclapfunction load-array ((n arg_z))
955 (check-nargs 1)
956 (with-altivec-registers (vr1 vr2 vr3 vr27) ; Clobbers imm0
957 (li imm0 ppc32::misc-data-offset)
958 (lvx vr1 arg_z imm0) ; load MSQ
959 (lvsl vr27 arg_z imm0) ; set the permute vector
960 (addi imm0 imm0 16) ; address of LSQ
961 (lvx vr2 arg_z imm0) ; load LSQ
962 (vperm vr3 vr1 vr2 vr27) ; aligned result appears in VR3
963 (dbg t)) ; Look at result in some debugger
964 (blr))
965|#
966
967;;; see "Optimizing PowerPC Code" p. 156
968;;; Note that the constant #x4330000080000000 is now in fp-s32conv
969
970(defppclapmacro int-to-freg (int freg imm)
971 (target-arch-case
972 (:ppc32
973 `(let ((temp 8)
974 (temp.h 8)
975 (temp.l 12))
976 (stwu tsp -16 tsp)
977 (stw tsp 4 tsp)
978 (stfd ppc::fp-s32conv temp tsp)
979 (unbox-fixnum ,imm ,int)
980 (xoris ,imm ,imm #x8000) ; invert sign of unboxed fixnum
981 (stw ,imm temp.l tsp)
982 (lfd ,freg temp tsp)
983 (lwz tsp 0 tsp)
984 (fsub ,freg ,freg ppc::fp-s32conv)))
985 (:ppc64
986 `(progn
987 (unbox-fixnum ,imm ,int)
988 (std ,imm -8 sp)
989 (lfd ,freg -8 sp)
990 (fcfid ,freg ,freg)))))
991
992;;; Set the most significant bit in DEST, clear all other bits.
993(defppclapmacro load-highbit (dest)
994 (target-arch-case
995 (:ppc32
996 `(lis ,dest #x8000))
997 (:ppc64
998 `(progn
999 (lis ,dest #x8000)
1000 (sldi ,dest ,dest 32)))))
1001
1002(defppclapmacro extract-bit-shift-count (dest src)
1003 (target-arch-case
1004 (:ppc32 `(clrlwi ,dest ,src (- 32 ppc32::bitmap-shift)))
1005 (:ppc64 `(clrldi ,dest ,src (- 64 ppc64::bitmap-shift)))))
1006
1007;;; "index" is the result of subtracting a base address from some
1008;;; possibly tagged pointer. "bitwords" is the address of the first
1009;;; word of an (untagged) bitvector.
1010(defppclapmacro set-bit-at-index (bitwords index &optional (mask ppc::imm3) (count ppc::imm4) (was ppc::imm1))
1011 (let* ((done (gensym))
1012 (again (gensym)))
1013 `(progn
1014 (load-highbit ,mask)
1015 (srri ,index ,index ,(target-arch-case
1016 (:ppc32 ppc32::dnode-shift)
1017 (:ppc64 ppc64::dnode-shift)))
1018 (extract-bit-shift-count ,count ,index)
1019 (srr ,mask ,mask ,count)
1020 (srri ,index ,index ,(target-arch-case
1021 (:ppc32 ppc32::bitmap-shift)
1022 (:ppc64 ppc64::bitmap-shift)))
1023 (slri ,index ,index ,(target-arch-case
1024 (:ppc32 ppc32::word-shift)
1025 (:ppc64 ppc64::word-shift)))
1026 (ldrx ,was ,bitwords ,index)
1027 (and. ,was ,was ,mask)
1028 (bne ,done)
1029 ,again
1030 (lrarx ,was ,bitwords ,index)
1031 (or ,was ,was ,mask)
1032 (strcx. ,was ,bitwords ,index)
1033 (bne ,again)
1034 ,done)))
1035
1036;;; Like SET-BIT-AT-INDEX, but sets CR0[EQ] iff the index'th bit
1037;;; is set.
1038(defppclapmacro test-bit-at-index (bitwords index &optional (mask ppc::imm3) (count ppc::imm4) (was ppc::imm1))
1039 `(progn
1040 (load-highbit ,mask)
1041 (srri ,index ,index ,(target-arch-case
1042 (:ppc32 ppc32::dnode-shift)
1043 (:ppc64 ppc64::dnode-shift)))
1044 (extract-bit-shift-count ,count ,index)
1045 (srr ,mask ,mask ,count)
1046 (srri ,index ,index ,(target-arch-case
1047 (:ppc32 ppc32::bitmap-shift)
1048 (:ppc64 ppc64::bitmap-shift)))
1049 (slri ,index ,index ,(target-arch-case
1050 (:ppc32 ppc32::word-shift)
1051 (:ppc64 ppc64::word-shift)))
1052 (ldrx ,was ,bitwords ,index)
1053 (and. ,mask ,was ,mask)))
1054
1055
1056(provide "PPC-LAPMACROS")
1057
1058;;; end of ppc-lapmacros.lisp
Note: See TracBrowser for help on using the repository browser.