0.7.1.20:
authorWilliam Harold Newman <william.newman@airmail.net>
Fri, 15 Feb 2002 17:10:02 +0000 (17:10 +0000)
committerWilliam Harold Newman <william.newman@airmail.net>
Fri, 15 Feb 2002 17:10:02 +0000 (17:10 +0000)
merged CSR SPARC port patch (sbcl-devel 2002-02-12, plus
lotso new files through FTP)
tweaking patch...
...s/ARCH_HAS_FOO/ARCH_HAS_FOO_IN_SIGCONTEXT/
...updated sbcl.1
...added 'typedef os_context_register' for OpenBSD
...added ARCH_HAS_STACK_POINTER for x86 (and added
x86-arch.h to hold it)
...renamed fpregister and fp.register to float.register (to
avoid the ambiguity with "frame pointer" that I
experienced when first trying to figure this out,
since even though for a given architecture it's pretty
unambiguous, in architecture-neutral code it's not)
...added x86-bsd-os.h

72 files changed:
NEWS
TODO
build-order.lisp-expr
doc/sbcl.1
make-config.sh
src/assembly/sparc/alloc.lisp [new file with mode: 0644]
src/assembly/sparc/arith.lisp [new file with mode: 0644]
src/assembly/sparc/array.lisp [new file with mode: 0644]
src/assembly/sparc/assem-rtns.lisp [new file with mode: 0644]
src/assembly/sparc/support.lisp [new file with mode: 0644]
src/code/alpha-vm.lisp
src/code/cold-init.lisp
src/code/sc-offset.lisp [new file with mode: 0644]
src/code/sparc-vm.lisp [new file with mode: 0644]
src/code/target-hash-table.lisp
src/cold/warm.lisp
src/compiler/aliencomp.lisp
src/compiler/dump.lisp
src/compiler/early-aliencomp.lisp [new file with mode: 0644]
src/compiler/generic/genesis.lisp
src/compiler/sparc/alloc.lisp [new file with mode: 0644]
src/compiler/sparc/arith.lisp [new file with mode: 0644]
src/compiler/sparc/array.lisp [new file with mode: 0644]
src/compiler/sparc/backend-parms.lisp [new file with mode: 0644]
src/compiler/sparc/c-call.lisp [new file with mode: 0644]
src/compiler/sparc/call.lisp [new file with mode: 0644]
src/compiler/sparc/cell.lisp [new file with mode: 0644]
src/compiler/sparc/char.lisp [new file with mode: 0644]
src/compiler/sparc/debug.lisp [new file with mode: 0644]
src/compiler/sparc/float.lisp [new file with mode: 0644]
src/compiler/sparc/insts.lisp [new file with mode: 0644]
src/compiler/sparc/macros.lisp [new file with mode: 0644]
src/compiler/sparc/memory.lisp [new file with mode: 0644]
src/compiler/sparc/move.lisp [new file with mode: 0644]
src/compiler/sparc/nlx.lisp [new file with mode: 0644]
src/compiler/sparc/parms.lisp [new file with mode: 0644]
src/compiler/sparc/pred.lisp [new file with mode: 0644]
src/compiler/sparc/sap.lisp [new file with mode: 0644]
src/compiler/sparc/show.lisp [new file with mode: 0644]
src/compiler/sparc/static-fn.lisp [new file with mode: 0644]
src/compiler/sparc/subprim.lisp [new file with mode: 0644]
src/compiler/sparc/system.lisp [new file with mode: 0644]
src/compiler/sparc/target-insts.lisp [new file with mode: 0644]
src/compiler/sparc/type-vops.lisp [new file with mode: 0644]
src/compiler/sparc/values.lisp [new file with mode: 0644]
src/compiler/sparc/vm.lisp [new file with mode: 0644]
src/runtime/Config.sparc-linux [new file with mode: 0644]
src/runtime/alpha-arch.c
src/runtime/alpha-arch.h [new file with mode: 0644]
src/runtime/alpha-linux-os.c
src/runtime/alpha-linux-os.h [new file with mode: 0644]
src/runtime/bsd-os.h
src/runtime/gc.c
src/runtime/interrupt.c
src/runtime/linux-os.c
src/runtime/linux-os.h
src/runtime/lispregs.h
src/runtime/os-common.c
src/runtime/os.h
src/runtime/print.c
src/runtime/purify.c
src/runtime/sparc-arch.c [new file with mode: 0644]
src/runtime/sparc-arch.h [new file with mode: 0644]
src/runtime/sparc-assem.S [new file with mode: 0644]
src/runtime/sparc-linux-os.c [new file with mode: 0644]
src/runtime/sparc-linux-os.h [new file with mode: 0644]
src/runtime/sparc-lispregs.h [new file with mode: 0644]
src/runtime/x86-arch.h [new file with mode: 0644]
src/runtime/x86-bsd-os.h [new file with mode: 0644]
src/runtime/x86-linux-os.c
src/runtime/x86-linux-os.h [new file with mode: 0644]
version.lisp-expr

diff --git a/NEWS b/NEWS
index 0a0ad46..fda5069 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1010,6 +1010,9 @@ changes in sbcl-0.7.2 relative to sbcl-0.7.1:
     (> SPEED DEBUG). (This is an incompatible change because there are
     programs which relied on the old CMU-CL-style behavior to optimize
     away their unbounded recursion which will now die of stack overflow.)
     (> SPEED DEBUG). (This is an incompatible change because there are
     programs which relied on the old CMU-CL-style behavior to optimize
     away their unbounded recursion which will now die of stack overflow.)
+  * SBCL runs on SPARC systems now. (thanks to Christophe Rhodes' port
+    of CMU CL's support for SPARC, and various endianness and other 
+    SBCL portability fixes due to Christophe Rhodes and Dan Barlow)
   * new syntactic sugar for the Unix command line: --load foo.bar is now
     an alternate notation for --eval '(load "foo.bar")'.
   * bug fixes:
   * new syntactic sugar for the Unix command line: --load foo.bar is now
     an alternate notation for --eval '(load "foo.bar")'.
   * bug fixes:
diff --git a/TODO b/TODO
index 2f07eb5..79bc782 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,11 +1,6 @@
 for early 0.7.x:
 
 for early 0.7.x:
 
-* building with CLISP (or explaining why not). This will likely involve
-       a rearrangement of the build system so that it never renames
-       the output from COMPILE-FILE, because CLISP's COMPILE-FILE
-       outputs two (!) files and as far as I can tell LOAD uses both
-       of them. Since I have other motivations for this rearrangement
-       besides CLISPiosyncrasies, I'm reasonably motivated to do it.
+* building with CLISP (or explaining why not)
 * urgent EVAL/EVAL-WHEN/%COMPILE/DEFUN/DEFSTRUCT cleanup:
        ** made inlining DEFUN inside MACROLET work again
        ** (also, while working on INLINE anyway, it might be easy
 * urgent EVAL/EVAL-WHEN/%COMPILE/DEFUN/DEFSTRUCT cleanup:
        ** made inlining DEFUN inside MACROLET work again
        ** (also, while working on INLINE anyway, it might be easy
index d3a121e..d8f8445 100644 (file)
  #!+bsd   ("src/code/bsd-os"   :not-host)
  #!+linux ("src/code/linux-os" :not-host)
 
  #!+bsd   ("src/code/bsd-os"   :not-host)
  #!+linux ("src/code/linux-os" :not-host)
 
+ ;; sparc-vm and ppc-vm need sc-offset defined to get at internal
+ ;; error args. This file contains stuff previously in
+ ;; debug-info.lisp.  Should it therefore be :not-host?  -- CSR,
+ ;; 2002-02-05
+ ("src/code/sc-offset")
  ;; KLUDGE: I'd prefer to have this done with a "code/target" softlink
  ;; instead of a bunch of reader macros. -- WHN 19990308
  #!+pmax ("src/code/pmax-vm" :not-host)
  ;; KLUDGE: I'd prefer to have this done with a "code/target" softlink
  ;; instead of a bunch of reader macros. -- WHN 19990308
  #!+pmax ("src/code/pmax-vm" :not-host)
  #!+rt    ("src/code/rt-vm"    :not-host)
  #!+hppa  ("src/code/hppa-vm"  :not-host)
  #!+x86   ("src/code/x86-vm"   :not-host)
  #!+rt    ("src/code/rt-vm"    :not-host)
  #!+hppa  ("src/code/hppa-vm"  :not-host)
  #!+x86   ("src/code/x86-vm"   :not-host)
+ #!+ppc   ("src/code/ppc-vm"   :not-host)
  #!+alpha ("src/code/alpha-vm" :not-host)
  #!+sgi   ("src/code/sgi-vm"   :not-host)
 
  #!+alpha ("src/code/alpha-vm" :not-host)
  #!+sgi   ("src/code/sgi-vm"   :not-host)
 
  ("src/compiler/target/char")
  ("src/compiler/target/memory")
  ("src/compiler/target/static-fn")
  ("src/compiler/target/char")
  ("src/compiler/target/memory")
  ("src/compiler/target/static-fn")
- ("src/compiler/target/arith")
+ ("src/compiler/target/arith"
+  ;; KLUDGE: for ppc and sparc this appears to be necessary -- see the
+  ;; comment below regarding src/compiler/target/array -- CSR,
+  ;; 2002-05-05
+  :ignore-failure-p) 
  ("src/compiler/target/subprim")
 
  ("src/compiler/target/debug")
  ("src/compiler/target/subprim")
 
  ("src/compiler/target/debug")
+ ;; src/compiler/sparc/c-call contains a deftransform for
+ ;; %ALIEN-FUNCALL -- CSR
+ ("src/compiler/early-aliencomp")
  ("src/compiler/target/c-call")
  ("src/compiler/target/cell")
  ("src/compiler/target/values")
  ("src/compiler/target/c-call")
  ("src/compiler/target/cell")
  ("src/compiler/target/values")
index 34a6163..5524b86 100644 (file)
@@ -345,10 +345,10 @@ chance to see it.
 
 .SH SYSTEM REQUIREMENTS
 
 
 .SH SYSTEM REQUIREMENTS
 
-Unlike its distinguished ancestor CMU CL, SBCL currently runs only on X86
-(Linux, FreeBSD, and OpenBSD) and Alpha (Linux). For information on 
-other ongoing ports, see the sbcl-devel mailing list, and/or the
-web site.
+Unlike its distinguished ancestor CMU CL, SBCL currently runs only on
+X86 (Linux, FreeBSD, and OpenBSD), Alpha (Linux), and SPARC (Linux).
+For information on other ongoing and possible ports, see the
+sbcl-devel mailing list, and/or the web site.
 
 SBCL requires on the order of 16Mb RAM to run on X86 systems. 
 
 
 SBCL requires on the order of 16Mb RAM to run on X86 systems. 
 
index fb03490..68972cb 100644 (file)
@@ -32,6 +32,8 @@ echo //guessing default target CPU architecture from host architecture
 case `uname -m` in 
     *86) guessed_sbcl_arch=x86 ;; 
     [Aa]lpha) guessed_sbcl_arch=alpha ;;
 case `uname -m` in 
     *86) guessed_sbcl_arch=x86 ;; 
     [Aa]lpha) guessed_sbcl_arch=alpha ;;
+    sparc*) guessed_sbcl_arch=sparc ;;
+    ppc) guessed_sbcl_arch=ppc ;;
     *)
         # If we're not building on a supported target architecture, we
        # we have no guess, but it's not an error yet, since maybe
     *)
         # If we're not building on a supported target architecture, we
        # we have no guess, but it's not an error yet, since maybe
@@ -70,14 +72,23 @@ done
 echo //setting up OS-dependent information
 original_dir=`pwd`
 cd src/runtime/
 echo //setting up OS-dependent information
 original_dir=`pwd`
 cd src/runtime/
-rm -f Config
+rm -f Config target-arch-os.h target-arch.h target-os.h target-lispregs.h
+# KLUDGE: these two logically belong in the previous section
+# ("architecture-dependent"); it seems silly to enforce this in terms
+# of the shell script, though. -- CSR, 2002-02-03
+ln -s $sbcl_arch-arch.h target-arch.h
+ln -s $sbcl_arch-lispregs.h target-lispregs.h
 case `uname` in 
     Linux)
        echo -n ' :linux' >> $ltf
        ln -s Config.$sbcl_arch-linux Config
 case `uname` in 
     Linux)
        echo -n ' :linux' >> $ltf
        ln -s Config.$sbcl_arch-linux Config
+       ln -s $sbcl_arch-linux-os.h target-arch-os.h
+       ln -s linux-os.h target-os.h
        ;;
     *BSD)
        echo -n ' :bsd' >> $ltf
        ;;
     *BSD)
        echo -n ' :bsd' >> $ltf
+       ln -s $sbcl_arch-bsd-os.h target-arch-os.h
+       ln -s bsd-os.h target-os.h
        case `uname` in
            FreeBSD)
                echo -n ' :freebsd' >> $ltf
        case `uname` in
            FreeBSD)
                echo -n ' :freebsd' >> $ltf
diff --git a/src/assembly/sparc/alloc.lisp b/src/assembly/sparc/alloc.lisp
new file mode 100644 (file)
index 0000000..0a7e353
--- /dev/null
@@ -0,0 +1,16 @@
+;;;; stuff to handle allocation of stuff we don't want to do inline
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+;;; (Given that the pseudo-atomic sequence is so short, there is
+;;; nothing that qualifies.  But we want to keep the file around
+;;; in case we decide to add something later.)
diff --git a/src/assembly/sparc/arith.lisp b/src/assembly/sparc/arith.lisp
new file mode 100644 (file)
index 0000000..3864d7b
--- /dev/null
@@ -0,0 +1,573 @@
+;;;; Stuff to handle simple cases for generic arithmetic.
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; Addition and subtraction.
+
+(define-assembly-routine (generic-+
+                         (:cost 10)
+                         (:return-style :full-call)
+                         (:translate +)
+                         (:policy :safe)
+                         (:save-p t))
+                        ((:arg x (descriptor-reg any-reg) a0-offset)
+                         (:arg y (descriptor-reg any-reg) a1-offset)
+
+                         (:res res (descriptor-reg any-reg) a0-offset)
+
+                         (:temp temp non-descriptor-reg nl0-offset)
+                         (:temp temp2 non-descriptor-reg nl1-offset)
+                         (:temp lra descriptor-reg lra-offset)
+                         (:temp nargs any-reg nargs-offset)
+                         (:temp ocfp any-reg ocfp-offset))
+  (inst andcc zero-tn x fixnum-tag-mask)
+  (inst b :ne DO-STATIC-FUN)
+  (inst andcc zero-tn y fixnum-tag-mask)
+  (inst b :ne DO-STATIC-FUN)
+  (inst nop)
+  (inst addcc temp x y)
+  (inst b :vc done)
+  (inst nop)
+
+  (inst sra temp x fixnum-tag-bits)
+  (inst sra temp2 y fixnum-tag-bits)
+  (inst add temp2 temp)
+  (with-fixed-allocation (res temp bignum-widetag (1+ bignum-digits-offset))
+    (storew temp2 res bignum-digits-offset other-pointer-lowtag))
+  (lisp-return lra :offset 2)
+
+  DO-STATIC-FUN
+  (inst ld code-tn null-tn (static-fun-offset 'two-arg-+))
+  (inst li nargs (fixnumize 2))
+  (inst move ocfp cfp-tn)
+  (inst j code-tn
+       (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
+  (inst move cfp-tn csp-tn)
+
+  DONE
+  (move res temp))
+
+
+(define-assembly-routine (generic--
+                         (:cost 10)
+                         (:return-style :full-call)
+                         (:translate -)
+                         (:policy :safe)
+                         (:save-p t))
+                        ((:arg x (descriptor-reg any-reg) a0-offset)
+                         (:arg y (descriptor-reg any-reg) a1-offset)
+
+                         (:res res (descriptor-reg any-reg) a0-offset)
+
+                         (:temp temp non-descriptor-reg nl0-offset)
+                         (:temp temp2 non-descriptor-reg nl1-offset)
+                         (:temp lra descriptor-reg lra-offset)
+                         (:temp nargs any-reg nargs-offset)
+                         (:temp ocfp any-reg ocfp-offset))
+  (inst andcc zero-tn x fixnum-tag-mask)
+  (inst b :ne DO-STATIC-FUN)
+  (inst andcc zero-tn y fixnum-tag-mask)
+  (inst b :ne DO-STATIC-FUN)
+  (inst nop)
+  (inst subcc temp x y)
+  (inst b :vc done)
+  (inst nop)
+
+  (inst sra temp x fixnum-tag-bits)
+  (inst sra temp2 y fixnum-tag-bits)
+  (inst sub temp2 temp temp2)
+  (with-fixed-allocation (res temp bignum-widetag (1+ bignum-digits-offset))
+    (storew temp2 res bignum-digits-offset other-pointer-lowtag))
+  (lisp-return lra :offset 2)
+
+  DO-STATIC-FUN
+  (inst ld code-tn null-tn (static-fun-offset 'two-arg--))
+  (inst li nargs (fixnumize 2))
+  (inst move ocfp cfp-tn)
+  (inst j code-tn
+       (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
+  (inst move cfp-tn csp-tn)
+
+  DONE
+  (move res temp))
+
+
+\f
+;;;; Multiplication
+
+
+(define-assembly-routine (generic-*
+                         (:cost 50)
+                         (:return-style :full-call)
+                         (:translate *)
+                         (:policy :safe)
+                         (:save-p t))
+                        ((:arg x (descriptor-reg any-reg) a0-offset)
+                         (:arg y (descriptor-reg any-reg) a1-offset)
+
+                         (:res res (descriptor-reg any-reg) a0-offset)
+
+                         (:temp temp non-descriptor-reg nl0-offset)
+                         (:temp lo non-descriptor-reg nl1-offset)
+                         (:temp hi non-descriptor-reg nl2-offset)
+                         (:temp lra descriptor-reg lra-offset)
+                         (:temp nargs any-reg nargs-offset)
+                         (:temp ocfp any-reg ocfp-offset))
+  ;; If either arg is not a fixnum, call the static function.
+  (inst andcc zero-tn x fixnum-tag-mask)
+  (inst b :ne DO-STATIC-FUN)
+  (inst andcc zero-tn y fixnum-tag-mask)
+  (inst b :ne DO-STATIC-FUN)
+  (inst nop)
+
+  ;; Remove the tag from one arg so that the result will have the correct
+  ;; fixnum tag.
+  (inst sra temp x fixnum-tag-bits)
+  ;; Compute the produce temp * y and return the double-word product
+  ;; in hi:lo.
+  ;;
+  ;; FIXME: Note that the below shebang read-time conditionals aren't
+  ;; actually shebang. This is because the assembly files are also
+  ;; built in warm-init, when #! is not a defined read-macro. This
+  ;; problem will actually go away when we rewrite these low-level
+  ;; bits and pieces to use the backend-subfeatures machinery, as we
+  ;; will then conditionalize at code-emission time or assembly time
+  ;; for the VOP and the assembly routine respectively. - CSR,
+  ;; 2002-02-11
+  #+:sparc-64
+  ;; Sign extend y to a full 64-bits.  temp was already
+  ;; sign-extended by the sra instruction above.
+  (progn 
+    (inst sra y 0)
+    (inst mulx hi temp y)
+    (inst move lo hi)
+    (inst srax hi 32))
+  #+(and (not :sparc-64) (or :sparc-v8 :sparc-v9))
+  (progn
+    (inst smul lo temp y)
+    (inst rdy hi))
+  #+(and (not :sparc-64) (not (or :sparc-v8 :sparc-v9)))
+  (let ((MULTIPLIER-POSITIVE (gen-label)))
+    (inst wry temp)
+    (inst andcc hi zero-tn)
+    (inst nop)
+    (inst nop)
+    (dotimes (i 32)
+      (inst mulscc hi y))
+    (inst mulscc hi zero-tn)
+    (inst cmp x)
+    (inst b :ge MULTIPLIER-POSITIVE)
+    (inst nop)
+    (inst sub hi y)
+    (emit-label MULTIPLIER-POSITIVE)
+    (inst rdy lo))
+
+  ;; Check to see if the result will fit in a fixnum.  (I.e. the high word
+  ;; is just 32 copies of the sign bit of the low word).
+  (inst sra temp lo 31)
+  (inst xorcc temp hi)
+  (inst b :eq LOW-FITS-IN-FIXNUM)
+  ;; Shift the double word hi:lo down two bits to get rid of the fixnum tag.
+  (inst sll temp hi 30)
+  (inst srl lo fixnum-tag-bits)
+  (inst or lo temp)
+  (inst sra hi fixnum-tag-bits)
+  ;; Allocate a BIGNUM for the result.
+  #+nil
+  (pseudo-atomic (:extra (pad-data-block (1+ bignum-digits-offset)))
+    (let ((one-word (gen-label)))
+      (inst or res alloc-tn other-pointer-lowtag)
+      ;; We start out assuming that we need one word.  Is that correct?
+      (inst sra temp lo 31)
+      (inst xorcc temp hi)
+      (inst b :eq one-word)
+      (inst li temp (logior (ash 1 n-widetag-bits) bignum-widetag))
+      ;; Nope, we need two, so allocate the addition space.
+      (inst add alloc-tn (- (pad-data-block (+ 2 bignum-digits-offset))
+                           (pad-data-block (1+ bignum-digits-offset))))
+      (inst li temp (logior (ash 2 n-widetag-bits) bignum-widetag))
+      (storew hi res (1+ bignum-digits-offset) other-pointer-lowtag)
+      (emit-label one-word)
+      (storew temp res 0 other-pointer-lowtag)
+      (storew lo res bignum-digits-offset other-pointer-lowtag)))
+  ;; Always allocate 2 words for the bignum result, even if we only
+  ;; need one.  The copying GC will take care of the extra word if it
+  ;; isn't needed.
+  (with-fixed-allocation
+      (res temp bignum-widetag (+ 2 bignum-digits-offset))
+    (let ((one-word (gen-label)))
+      (inst or res alloc-tn other-pointer-lowtag)
+      ;; We start out assuming that we need one word.  Is that correct?
+      (inst sra temp lo 31)
+      (inst xorcc temp hi)
+      (inst b :eq one-word)
+      (inst li temp (logior (ash 1 n-widetag-bits) bignum-widetag))
+      ;; Need 2 words.  Set the header appropriately, and save the
+      ;; high and low parts.
+      (inst li temp (logior (ash 2 n-widetag-bits) bignum-widetag))
+      (storew hi res (1+ bignum-digits-offset) other-pointer-lowtag)
+      (emit-label one-word)
+      (storew temp res 0 other-pointer-lowtag)
+      (storew lo res bignum-digits-offset other-pointer-lowtag)))
+  ;; Out of here
+  (lisp-return lra :offset 2)
+
+  DO-STATIC-FUN
+  (inst ld code-tn null-tn (static-fun-offset 'two-arg-*))
+  (inst li nargs (fixnumize 2))
+  (inst move ocfp cfp-tn)
+  (inst j code-tn
+       (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
+  (inst move cfp-tn csp-tn)
+
+  LOW-FITS-IN-FIXNUM
+  (move res lo))
+
+(macrolet
+    ((frob (name note cost type sc)
+       `(define-assembly-routine (,name
+                                 (:note ,note)
+                                 (:cost ,cost)
+                                 (:translate *)
+                                 (:policy :fast-safe)
+                                 (:arg-types ,type ,type)
+                                 (:result-types ,type))
+                                ((:arg x ,sc nl0-offset)
+                                 (:arg y ,sc nl1-offset)
+                                 (:res res ,sc nl0-offset)
+                                 (:temp temp ,sc nl2-offset))
+         ,@(when (eq type 'tagged-num)
+             `((inst sra x 2)))
+        #+:sparc-64
+        ;; Sign extend, then multiply
+        (progn
+          (inst sra x 0)
+          (inst sra y 0)
+          (inst mulx res x y))
+        #+(and (not :sparc-64) (or :sparc-v8 :sparc-v9))
+        (inst smul res x y)
+        #+(and (not :sparc-64) (not (or :sparc-v8 :sparc-v9)))
+        (progn
+          (inst wry x)
+          (inst andcc temp zero-tn)
+          (inst nop)
+          (inst nop)
+          (dotimes (i 32)
+            (inst mulscc temp y))
+          (inst mulscc temp zero-tn)
+          (inst rdy res)))))
+  (frob unsigned-* "unsigned *" 40 unsigned-num unsigned-reg)
+  (frob signed-* "unsigned *" 41 signed-num signed-reg)
+  (frob fixnum-* "fixnum *" 30 tagged-num any-reg))
+
+
+\f
+;;;; Division.
+
+#+sb-assembling
+(defun emit-divide-loop (divisor rem quo tagged)
+  (inst li quo 0)
+  (labels
+      ((do-loop (depth)
+        (cond
+         ((zerop depth)
+          (inst unimp 0))
+         (t
+          (let ((label-1 (gen-label))
+                (label-2 (gen-label)))
+            (inst cmp divisor rem)
+            (inst b :geu label-1)
+            (inst nop)
+            (inst sll divisor 1)
+            (do-loop (1- depth))
+            (inst srl divisor 1)
+            (inst cmp divisor rem)
+            (emit-label label-1)
+            (inst b :gtu label-2)
+            (inst sll quo 1)
+            (inst add quo (if tagged (fixnumize 1) 1))
+            (inst sub rem divisor)
+            (emit-label label-2))))))
+    (do-loop (if tagged 30 32))))
+
+(define-assembly-routine (positive-fixnum-truncate
+                         (:note "unsigned fixnum truncate")
+                         (:cost 45)
+                         (:translate truncate)
+                         (:policy :fast-safe)
+                         (:arg-types positive-fixnum positive-fixnum)
+                         (:result-types positive-fixnum positive-fixnum))
+                        ((:arg dividend any-reg nl0-offset)
+                         (:arg divisor any-reg nl1-offset)
+
+                         (:res quo any-reg nl2-offset)
+                         (:res rem any-reg nl0-offset))
+
+  (let ((error (generate-error-code nil division-by-zero-error
+                                   dividend divisor)))
+    (inst cmp divisor)
+    (inst b :eq error))
+
+  (move rem dividend)
+  (emit-divide-loop divisor rem quo t))
+
+
+(define-assembly-routine (fixnum-truncate
+                         (:note "fixnum truncate")
+                         (:cost 50)
+                         (:policy :fast-safe)
+                         (:translate truncate)
+                         (:arg-types tagged-num tagged-num)
+                         (:result-types tagged-num tagged-num))
+                        ((:arg dividend any-reg nl0-offset)
+                         (:arg divisor any-reg nl1-offset)
+
+                         (:res quo any-reg nl2-offset)
+                         (:res rem any-reg nl0-offset)
+
+                         (:temp quo-sign any-reg nl5-offset)
+                         (:temp rem-sign any-reg nargs-offset))
+  
+  (let ((error (generate-error-code nil division-by-zero-error
+                                   dividend divisor)))
+    (inst cmp divisor)
+    (inst b :eq error))
+
+  (inst xor quo-sign dividend divisor)
+  (inst move rem-sign dividend)
+  (let ((label (gen-label)))
+    (inst cmp dividend)
+    (inst ba :lt label)
+    (inst neg dividend)
+    (emit-label label))
+  (let ((label (gen-label)))
+    (inst cmp divisor)
+    (inst ba :lt label)
+    (inst neg divisor)
+    (emit-label label))
+  (move rem dividend)
+  (emit-divide-loop divisor rem quo t)
+  (let ((label (gen-label)))
+    ;; If the quo-sign is negative, we need to negate quo.
+    (inst cmp quo-sign)
+    (inst ba :lt label)
+    (inst neg quo)
+    (emit-label label))
+  (let ((label (gen-label)))
+    ;; If the rem-sign is negative, we need to negate rem.
+    (inst cmp rem-sign)
+    (inst ba :lt label)
+    (inst neg rem)
+    (emit-label label)))
+
+
+(define-assembly-routine (signed-truncate
+                         (:note "(signed-byte 32) truncate")
+                         (:cost 60)
+                         (:policy :fast-safe)
+                         (:translate truncate)
+                         (:arg-types signed-num signed-num)
+                         (:result-types signed-num signed-num))
+
+                        ((:arg dividend signed-reg nl0-offset)
+                         (:arg divisor signed-reg nl1-offset)
+
+                         (:res quo signed-reg nl2-offset)
+                         (:res rem signed-reg nl0-offset)
+
+                         (:temp quo-sign signed-reg nl5-offset)
+                         (:temp rem-sign signed-reg nargs-offset))
+  
+  (let ((error (generate-error-code nil division-by-zero-error
+                                   dividend divisor)))
+    (inst cmp divisor)
+    (inst b :eq error))
+
+  (inst xor quo-sign dividend divisor)
+  (inst move rem-sign dividend)
+  (let ((label (gen-label)))
+    (inst cmp dividend)
+    (inst ba :lt label)
+    (inst neg dividend)
+    (emit-label label))
+  (let ((label (gen-label)))
+    (inst cmp divisor)
+    (inst ba :lt label)
+    (inst neg divisor)
+    (emit-label label))
+  (move rem dividend)
+  (emit-divide-loop divisor rem quo nil)
+  (let ((label (gen-label)))
+    ;; If the quo-sign is negative, we need to negate quo.
+    (inst cmp quo-sign)
+    (inst ba :lt label)
+    (inst neg quo)
+    (emit-label label))
+  (let ((label (gen-label)))
+    ;; If the rem-sign is negative, we need to negate rem.
+    (inst cmp rem-sign)
+    (inst ba :lt label)
+    (inst neg rem)
+    (emit-label label)))
+
+\f
+;;;; Comparison
+
+(macrolet
+    ((define-cond-assem-rtn (name translate static-fn cmp)
+       `(define-assembly-routine (,name
+                                 (:cost 10)
+                                 (:return-style :full-call)
+                                 (:policy :safe)
+                                 (:translate ,translate)
+                                 (:save-p t))
+                                ((:arg x (descriptor-reg any-reg) a0-offset)
+                                 (:arg y (descriptor-reg any-reg) a1-offset)
+                                 
+                                 (:res res descriptor-reg a0-offset)
+                                 
+                                 (:temp nargs any-reg nargs-offset)
+                                 (:temp ocfp any-reg ocfp-offset))
+         (inst andcc zero-tn x fixnum-tag-mask)
+         (inst b :ne DO-STATIC-FN)
+         (inst andcc zero-tn y fixnum-tag-mask)
+         (inst b :eq DO-COMPARE)
+         (inst cmp x y)
+         
+         DO-STATIC-FN
+         (inst ld code-tn null-tn (static-fun-offset ',static-fn))
+         (inst li nargs (fixnumize 2))
+         (inst move ocfp cfp-tn)
+         (inst j code-tn
+               (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
+         (inst move cfp-tn csp-tn)
+         
+         DO-COMPARE
+         (inst b ,cmp done)
+         (load-symbol res t)
+         (inst move res null-tn)
+         DONE)))
+
+  (define-cond-assem-rtn generic-< < two-arg-< :lt)
+  (define-cond-assem-rtn generic-<= <= two-arg-<= :le)
+  (define-cond-assem-rtn generic-> > two-arg-> :gt)
+  (define-cond-assem-rtn generic->= >= two-arg->= :ge))
+
+
+(define-assembly-routine (generic-eql
+                         (:cost 10)
+                         (:return-style :full-call)
+                         (:policy :safe)
+                         (:translate eql)
+                         (:save-p t))
+                        ((:arg x (descriptor-reg any-reg) a0-offset)
+                         (:arg y (descriptor-reg any-reg) a1-offset)
+                         
+                         (:res res descriptor-reg a0-offset)
+
+                         (:temp lra descriptor-reg lra-offset)
+                         (:temp nargs any-reg nargs-offset)
+                         (:temp ocfp any-reg ocfp-offset))
+  (inst cmp x y)
+  (inst b :eq RETURN-T)
+  (inst andcc zero-tn x fixnum-tag-mask)
+  (inst b :eq RETURN-NIL)
+  (inst andcc zero-tn y fixnum-tag-mask)
+  (inst b :ne DO-STATIC-FN)
+  (inst nop)
+
+  RETURN-NIL
+  (inst move res null-tn)
+  (lisp-return lra :offset 2)
+
+  DO-STATIC-FN
+  (inst ld code-tn null-tn (static-fun-offset 'eql))
+  (inst li nargs (fixnumize 2))
+  (inst move ocfp cfp-tn)
+  (inst j code-tn
+       (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
+  (inst move cfp-tn csp-tn)
+
+  RETURN-T
+  (load-symbol res t))
+
+(define-assembly-routine (generic-=
+                         (:cost 10)
+                         (:return-style :full-call)
+                         (:policy :safe)
+                         (:translate =)
+                         (:save-p t))
+                        ((:arg x (descriptor-reg any-reg) a0-offset)
+                         (:arg y (descriptor-reg any-reg) a1-offset)
+
+                         (:res res descriptor-reg a0-offset)
+
+                         (:temp lra descriptor-reg lra-offset)
+                         (:temp nargs any-reg nargs-offset)
+                         (:temp ocfp any-reg ocfp-offset))
+  (inst andcc zero-tn x fixnum-tag-mask)
+  (inst b :ne DO-STATIC-FN)
+  (inst andcc zero-tn y fixnum-tag-mask)
+  (inst b :ne DO-STATIC-FN)
+  (inst cmp x y)
+  (inst b :eq RETURN-T)
+  (inst nop)
+
+  (inst move res null-tn)
+  (lisp-return lra :offset 2)
+
+  DO-STATIC-FN
+  (inst ld code-tn null-tn (static-fun-offset 'two-arg-=))
+  (inst li nargs (fixnumize 2))
+  (inst move ocfp cfp-tn)
+  (inst j code-tn
+       (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
+  (inst move cfp-tn csp-tn)
+
+  RETURN-T
+  (load-symbol res t))
+
+(define-assembly-routine (generic-/=
+                         (:cost 10)
+                         (:return-style :full-call)
+                         (:policy :safe)
+                         (:translate /=)
+                         (:save-p t))
+                        ((:arg x (descriptor-reg any-reg) a0-offset)
+                         (:arg y (descriptor-reg any-reg) a1-offset)
+
+                         (:res res descriptor-reg a0-offset)
+
+                         (:temp lra descriptor-reg lra-offset)
+                         (:temp nargs any-reg nargs-offset)
+                         (:temp ocfp any-reg ocfp-offset))
+  (inst cmp x y)
+  (inst b :eq RETURN-NIL)
+  (inst andcc zero-tn x fixnum-tag-mask)
+  (inst b :ne DO-STATIC-FN)
+  (inst andcc zero-tn y fixnum-tag-mask)
+  (inst b :ne DO-STATIC-FN)
+  (inst nop)
+
+  (load-symbol res t)
+  (lisp-return lra :offset 2)
+
+  DO-STATIC-FN
+  (inst ld code-tn null-tn (static-fun-offset 'two-arg-=))
+  (inst li nargs (fixnumize 2))
+  (inst move ocfp cfp-tn)
+  (inst j code-tn
+       (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
+  (inst move cfp-tn csp-tn)
+
+  RETURN-NIL
+  (inst move res null-tn))
diff --git a/src/assembly/sparc/array.lisp b/src/assembly/sparc/array.lisp
new file mode 100644 (file)
index 0000000..5b4f5fd
--- /dev/null
@@ -0,0 +1,114 @@
+;;;; support routines for arrays and vectors
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+(define-assembly-routine (allocate-vector
+                         (:policy :fast-safe)
+                         (:translate allocate-vector)
+                         (:arg-types positive-fixnum
+                                     positive-fixnum
+                                     positive-fixnum))
+                        ((:arg type any-reg a0-offset)
+                         (:arg length any-reg a1-offset)
+                         (:arg words any-reg a2-offset)
+                         (:res result descriptor-reg a0-offset)
+
+                         (:temp ndescr non-descriptor-reg nl0-offset)
+                         (:temp vector descriptor-reg a3-offset))
+  (pseudo-atomic ()
+    (inst or vector alloc-tn other-pointer-lowtag)
+    (inst add ndescr words (* (1+ vector-data-offset) n-word-bytes))
+    (inst andn ndescr 7)
+    (inst add alloc-tn ndescr)
+    (inst srl ndescr type word-shift)
+    (storew ndescr vector 0 other-pointer-lowtag)
+    (storew length vector vector-length-slot other-pointer-lowtag))
+  ;; This makes sure the zero byte at the end of a string is paged in so
+  ;; the kernel doesn't bitch if we pass it the string.
+  (storew zero-tn alloc-tn 0)
+  (move result vector))
+
+
+\f
+;;;; Hash primitives
+
+;;; this is commented out in the alpha port. I'm therefore going to
+;;; comment it out here pending explanation -- CSR, 2001-08-31.
+
+#|
+#+assembler
+(defparameter sxhash-simple-substring-entry (gen-label))
+
+(define-assembly-routine (sxhash-simple-string
+                         (:translate %sxhash-simple-string)
+                         (:policy :fast-safe)
+                         (:result-types positive-fixnum))
+                        ((:arg string descriptor-reg a0-offset)
+                         (:res result any-reg a0-offset)
+
+                         (:temp length any-reg a1-offset)
+                         (:temp accum non-descriptor-reg nl0-offset)
+                         (:temp data non-descriptor-reg nl1-offset)
+                         (:temp temp non-descriptor-reg nl2-offset)
+                         (:temp offset non-descriptor-reg nl3-offset))
+
+  (declare (ignore result accum data temp offset))
+
+  (inst b sxhash-simple-substring-entry)
+  (loadw length string vector-length-slot other-pointer-lowtag))
+
+
+(define-assembly-routine (sxhash-simple-substring
+                         (:translate %sxhash-simple-substring)
+                         (:policy :fast-safe)
+                         (:arg-types * positive-fixnum)
+                         (:result-types positive-fixnum))
+                        ((:arg string descriptor-reg a0-offset)
+                         (:arg length any-reg a1-offset)
+                         (:res result any-reg a0-offset)
+
+                         (:temp accum non-descriptor-reg nl0-offset)
+                         (:temp data non-descriptor-reg nl1-offset)
+                         (:temp temp non-descriptor-reg nl2-offset)
+                         (:temp offset non-descriptor-reg nl3-offset))
+  (emit-label sxhash-simple-substring-entry)
+
+  (inst li offset (- (* vector-data-offset n-word-bytes) other-pointer-lowtag))
+  (inst b test)
+  (move accum zero-tn)
+
+  LOOP
+
+  (inst xor accum data)
+  (inst sll temp accum 27)
+  (inst srl accum 5)
+  (inst or accum temp)
+  (inst add offset 4)
+
+  TEST
+
+  (inst subcc length (fixnumize 4))
+  (inst b :ge loop)
+  (inst ld data string offset)
+
+  (inst addcc length (fixnumize 4))
+  (inst b :eq done)
+  (inst neg length)
+  (inst sll length 1)
+  (inst srl data length)
+  (inst xor accum data)
+
+  DONE
+
+  (inst sll result accum 5)
+  (inst srl result result 3))
+|#
diff --git a/src/assembly/sparc/assem-rtns.lisp b/src/assembly/sparc/assem-rtns.lisp
new file mode 100644 (file)
index 0000000..c3fd3ef
--- /dev/null
@@ -0,0 +1,238 @@
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; Return-multiple with other than one value
+
+#+sb-assembling ;; we don't want a vop for this one.
+(define-assembly-routine
+    (return-multiple
+     (:return-style :none))
+
+     ;; These four are really arguments.
+    ((:temp nvals any-reg nargs-offset)
+     (:temp vals any-reg nl0-offset)
+     (:temp ocfp any-reg nl1-offset)
+     (:temp lra descriptor-reg lra-offset)
+
+     ;; These are just needed to facilitate the transfer
+     (:temp count any-reg nl2-offset)
+     (:temp src any-reg nl3-offset)
+     (:temp dst any-reg nl4-offset)
+     (:temp temp descriptor-reg l0-offset)
+
+     ;; These are needed so we can get at the register args.
+     (:temp a0 descriptor-reg a0-offset)
+     (:temp a1 descriptor-reg a1-offset)
+     (:temp a2 descriptor-reg a2-offset)
+     (:temp a3 descriptor-reg a3-offset)
+     (:temp a4 descriptor-reg a4-offset)
+     (:temp a5 descriptor-reg a5-offset))
+
+  ;; Note, because of the way the return-multiple vop is written, we can
+  ;; assume that we are never called with nvals == 1 and that a0 has already
+  ;; been loaded.
+  (inst cmp nvals)
+  (inst b :le default-a0-and-on)
+  (inst cmp nvals (fixnumize 2))
+  (inst b :le default-a2-and-on)
+  (inst ld a1 vals (* 1 n-word-bytes))
+  (inst cmp nvals (fixnumize 3))
+  (inst b :le default-a3-and-on)
+  (inst ld a2 vals (* 2 n-word-bytes))
+  (inst cmp nvals (fixnumize 4))
+  (inst b :le default-a4-and-on)
+  (inst ld a3 vals (* 3 n-word-bytes))
+  (inst cmp nvals (fixnumize 5))
+  (inst b :le default-a5-and-on)
+  (inst ld a4 vals (* 4 n-word-bytes))
+  (inst cmp nvals (fixnumize 6))
+  (inst b :le done)
+  (inst ld a5 vals (* 5 n-word-bytes))
+
+  ;; Copy the remaining args to the top of the stack.
+  (inst add src vals (* 6 n-word-bytes))
+  (inst add dst cfp-tn (* 6 n-word-bytes))
+  (inst subcc count nvals (fixnumize 6))
+
+  LOOP
+  (inst ld temp src)
+  (inst add src n-word-bytes)
+  (inst st temp dst)
+  (inst add dst n-word-bytes)
+  (inst b :gt loop)
+  (inst subcc count (fixnumize 1))
+               
+  (inst b done)
+  (inst nop)
+
+  DEFAULT-A0-AND-ON
+  (inst move a0 null-tn)
+  (inst move a1 null-tn)
+  DEFAULT-A2-AND-ON
+  (inst move a2 null-tn)
+  DEFAULT-A3-AND-ON
+  (inst move a3 null-tn)
+  DEFAULT-A4-AND-ON
+  (inst move a4 null-tn)
+  DEFAULT-A5-AND-ON
+  (inst move a5 null-tn)
+  DONE
+  
+  ;; Clear the stack.
+  (move ocfp-tn cfp-tn)
+  (move cfp-tn ocfp)
+  (inst add csp-tn ocfp-tn nvals)
+  
+  ;; Return.
+  (lisp-return lra))
+
+
+\f
+;;;; tail-call-variable.
+
+#+sb-assembling ;; no vop for this one either.
+(define-assembly-routine
+    (tail-call-variable
+     (:return-style :none))
+
+    ;; These are really args.
+    ((:temp args any-reg nl0-offset)
+     (:temp lexenv descriptor-reg lexenv-offset)
+
+     ;; We need to compute this
+     (:temp nargs any-reg nargs-offset)
+
+     ;; These are needed by the blitting code.
+     (:temp src any-reg nl1-offset)
+     (:temp dst any-reg nl2-offset)
+     (:temp count any-reg nl3-offset)
+     (:temp temp descriptor-reg l0-offset)
+
+     ;; These are needed so we can get at the register args.
+     (:temp a0 descriptor-reg a0-offset)
+     (:temp a1 descriptor-reg a1-offset)
+     (:temp a2 descriptor-reg a2-offset)
+     (:temp a3 descriptor-reg a3-offset)
+     (:temp a4 descriptor-reg a4-offset)
+     (:temp a5 descriptor-reg a5-offset))
+
+
+  ;; Calculate NARGS (as a fixnum)
+  (inst sub nargs csp-tn args)
+     
+  ;; Load the argument regs (must do this now, 'cause the blt might
+  ;; trash these locations)
+  (inst ld a0 args (* 0 n-word-bytes))
+  (inst ld a1 args (* 1 n-word-bytes))
+  (inst ld a2 args (* 2 n-word-bytes))
+  (inst ld a3 args (* 3 n-word-bytes))
+  (inst ld a4 args (* 4 n-word-bytes))
+  (inst ld a5 args (* 5 n-word-bytes))
+
+  ;; Calc SRC, DST, and COUNT
+  (inst addcc count nargs (fixnumize (- register-arg-count)))
+  (inst b :le done)
+  (inst add src args (* n-word-bytes register-arg-count))
+  (inst add dst cfp-tn (* n-word-bytes register-arg-count))
+       
+  LOOP
+  ;; Copy one arg.
+  (inst ld temp src)
+  (inst add src src n-word-bytes)
+  (inst st temp dst)
+  (inst addcc count (fixnumize -1))
+  (inst b :gt loop)
+  (inst add dst dst n-word-bytes)
+       
+  DONE
+  ;; We are done.  Do the jump.
+  (loadw temp lexenv closure-fun-slot fun-pointer-lowtag)
+  (lisp-jump temp))
+
+
+\f
+;;;; Non-local exit noise.
+
+(define-assembly-routine (unwind
+                         (:return-style :none)
+                         (:translate %continue-unwind)
+                         (:policy :fast-safe))
+                        ((:arg block (any-reg descriptor-reg) a0-offset)
+                         (:arg start (any-reg descriptor-reg) ocfp-offset)
+                         (:arg count (any-reg descriptor-reg) nargs-offset)
+                         (:temp lra descriptor-reg lra-offset)
+                         (:temp cur-uwp any-reg nl0-offset)
+                         (:temp next-uwp any-reg nl1-offset)
+                         (:temp target-uwp any-reg nl2-offset))
+  (declare (ignore start count))
+
+  (let ((error (generate-error-code nil invalid-unwind-error)))
+    (inst cmp block)
+    (inst b :eq error))
+  
+  (load-symbol-value cur-uwp *current-unwind-protect-block*)
+  (loadw target-uwp block unwind-block-current-uwp-slot)
+  (inst cmp cur-uwp target-uwp)
+  (inst b :ne do-uwp)
+  (inst nop)
+      
+  (move cur-uwp block)
+
+  DO-EXIT
+      
+  (loadw cfp-tn cur-uwp unwind-block-current-cont-slot)
+  (loadw code-tn cur-uwp unwind-block-current-code-slot)
+  (loadw lra cur-uwp unwind-block-entry-pc-slot)
+  (lisp-return lra :frob-code nil)
+
+  DO-UWP
+
+  (loadw next-uwp cur-uwp unwind-block-current-uwp-slot)
+  (inst b do-exit)
+  (store-symbol-value next-uwp *current-unwind-protect-block*))
+
+
+(define-assembly-routine (throw
+                         (:return-style :none))
+                        ((:arg target descriptor-reg a0-offset)
+                         (:arg start any-reg ocfp-offset)
+                         (:arg count any-reg nargs-offset)
+                         (:temp catch any-reg a1-offset)
+                         (:temp tag descriptor-reg a2-offset)
+                         (:temp temp non-descriptor-reg nl0-offset))
+  
+  (declare (ignore start count))
+
+  (load-symbol-value catch *current-catch-block*)
+  
+  loop
+  
+  (let ((error (generate-error-code nil unseen-throw-tag-error target)))
+    (inst cmp catch)
+    (inst b :eq error)
+    (inst nop))
+  
+  (loadw tag catch catch-block-tag-slot)
+  (inst cmp tag target)
+  (inst b :eq exit)
+  (inst nop)
+  (loadw catch catch catch-block-previous-catch-slot)
+  (inst b loop)
+  (inst nop)
+  
+  exit
+  
+  (move target catch)
+  (inst li temp (make-fixup 'unwind :assembly-routine))
+  (inst j temp)
+  (inst nop))
+
+
diff --git a/src/assembly/sparc/support.lisp b/src/assembly/sparc/support.lisp
new file mode 100644 (file)
index 0000000..d5a1532
--- /dev/null
@@ -0,0 +1,78 @@
+;;;; the machine-specific support routines needed by the file assembler
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+(!def-vm-support-routine generate-call-sequence (name style vop)
+  (ecase style
+    (:raw
+     (let ((temp (make-symbol "TEMP"))
+          (lip (make-symbol "LIP")))
+       (values 
+       `((inst jali ,lip ,temp (make-fixup ',name :assembly-routine))
+         (inst nop))
+       `((:temporary (:scs (non-descriptor-reg) :from (:eval 0) :to (:eval 1))
+                     ,temp)
+         (:temporary (:scs (interior-reg) :from (:eval 0) :to (:eval 1))
+                     ,lip)))))
+    (:full-call
+     (let ((temp (make-symbol "TEMP"))
+          (nfp-save (make-symbol "NFP-SAVE"))
+          (lra (make-symbol "LRA")))
+       (values
+       `((let ((lra-label (gen-label))
+               (cur-nfp (current-nfp-tn ,vop)))
+           (when cur-nfp
+             (store-stack-tn ,nfp-save cur-nfp))
+           (inst compute-lra-from-code ,lra code-tn lra-label ,temp)
+           (note-next-instruction ,vop :call-site)
+           (inst ji ,temp (make-fixup ',name :assembly-routine))
+           (inst nop)
+           (emit-return-pc lra-label)
+           (note-this-location ,vop :single-value-return)
+           (without-scheduling ()
+             (move csp-tn ocfp-tn)
+             (inst nop))
+           (inst compute-code-from-lra code-tn code-tn
+                 lra-label ,temp)
+           (when cur-nfp
+             (load-stack-tn cur-nfp ,nfp-save))))
+       `((:temporary (:scs (non-descriptor-reg) :from (:eval 0) :to (:eval 1))
+                     ,temp)
+         (:temporary (:sc descriptor-reg :offset lra-offset
+                          :from (:eval 0) :to (:eval 1))
+                     ,lra)
+         (:temporary (:scs (control-stack) :offset nfp-save-offset)
+                     ,nfp-save)
+         (:save-p :compute-only)))))
+    (:none
+     (let ((temp (make-symbol "TEMP")))
+       (values 
+       `((inst ji ,temp (make-fixup ',name :assembly-routine))
+         (inst nop))
+       `((:temporary (:scs (non-descriptor-reg) :from (:eval 0) :to (:eval 1))
+                     ,temp)))))))
+
+(!def-vm-support-routine generate-return-sequence (style)
+  (ecase style
+    (:raw
+     `((inst j
+            (make-random-tn :kind :normal
+                            :sc (sc-or-lose 'interior-reg)
+                            :offset lip-offset)
+            8)
+       (inst nop)))
+    (:full-call
+     `((lisp-return (make-random-tn :kind :normal
+                                   :sc (sc-or-lose 'descriptor-reg)
+                                   :offset lra-offset)
+                   :offset 2)))
+    (:none)))
index e9a1c54..f6753b8 100644 (file)
 
 ;;; FIXME: Whether COERCE actually knows how to make a float out of a
 ;;; long is another question. This stuff still needs testing.
 
 ;;; FIXME: Whether COERCE actually knows how to make a float out of a
 ;;; long is another question. This stuff still needs testing.
-(define-alien-routine ("os_context_fpregister_addr"
+(define-alien-routine ("os_context_float_register_addr"
                       context-float-register-addr)
   (* long)
   (context (* os-context-t))
                       context-float-register-addr)
   (* long)
   (context (* os-context-t))
index 02bdfd9..260ae43 100644 (file)
   ;; Barlow's Alpha patches suppress it for Alpha. Why the difference?
   #!+alpha
   (set-floating-point-modes :traps '(:overflow
   ;; Barlow's Alpha patches suppress it for Alpha. Why the difference?
   #!+alpha
   (set-floating-point-modes :traps '(:overflow
-                                    #!-x86 :underflow
+                                    #!+alpha :underflow
                                     :invalid
                                     :divide-by-zero))
 
                                     :invalid
                                     :divide-by-zero))
 
@@ -289,7 +289,7 @@ instead (which is another name for the same thing)."))
                                  ;; disabled by default. Joe User can
                                  ;; explicitly enable them if
                                  ;; desired.
                                  ;; disabled by default. Joe User can
                                  ;; explicitly enable them if
                                  ;; desired.
-                                 #!-x86 :underflow))
+                                 #!+alpha :underflow))
       ;; Clear pseudo atomic in case this core wasn't compiled with
       ;; support.
       ;;
       ;; Clear pseudo atomic in case this core wasn't compiled with
       ;; support.
       ;;
diff --git a/src/code/sc-offset.lisp b/src/code/sc-offset.lisp
new file mode 100644 (file)
index 0000000..001367c
--- /dev/null
@@ -0,0 +1,28 @@
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+;;; SC-OFFSETs are needed by sparc-vm.lisp
+
+(in-package "SB!C")
+\f
+;;;; SC-OFFSETs
+;;;;
+;;;; We represent the place where some value is stored with a SC-OFFSET,
+;;;; which is the SC number and offset encoded as an integer.
+
+(defconstant-eqx sc-offset-scn-byte (byte 5 0) #'equalp)
+(defconstant-eqx sc-offset-offset-byte (byte 22 5) #'equalp)
+(def!type sc-offset () '(unsigned-byte 27))
+
+(defmacro make-sc-offset (scn offset)
+  `(dpb ,scn sc-offset-scn-byte
+       (dpb ,offset sc-offset-offset-byte 0)))
+
+(defmacro sc-offset-scn (sco) `(ldb sc-offset-scn-byte ,sco))
+(defmacro sc-offset-offset (sco) `(ldb sc-offset-offset-byte ,sco))
diff --git a/src/code/sparc-vm.lisp b/src/code/sparc-vm.lisp
new file mode 100644 (file)
index 0000000..c7f39f2
--- /dev/null
@@ -0,0 +1,201 @@
+;;;; SPARC-specific runtime stuff
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+(in-package "SB!VM")
+
+\f
+
+;;; See x86-vm.lisp for a description of this.
+(define-alien-type os-context-t (struct os-context-t-struct))
+
+
+\f
+;;;; MACHINE-TYPE and MACHINE-VERSION
+
+(defun machine-type ()
+  "Returns a string describing the type of the local machine."
+  "SPARC")
+
+(defun machine-version ()
+  "Returns a string describing the version of the local machine."
+  "SPARC")
+
+\f
+(defun fixup-code-object (code offset fixup kind)
+  (declare (type index offset))
+  (unless (zerop (rem offset n-word-bytes))
+    (error "Unaligned instruction?  offset=#x~X." offset))
+  (sb!sys:without-gcing
+   (let ((sap (truly-the system-area-pointer
+                        (%primitive sb!kernel::code-instructions code))))
+     (ecase kind
+       (:call
+       (error "Can't deal with CALL fixups, yet."))
+       (:sethi
+       (setf (ldb (byte 22 0) (sap-ref-32 sap offset))
+             (ldb (byte 22 10) fixup)))
+       (:add
+       (setf (ldb (byte 10 0) (sap-ref-32 sap offset))
+             (ldb (byte 10 0) fixup)))))))
+
+\f
+;;;; "Sigcontext" access functions, cut & pasted from alpha-vm.lisp.
+;;;;
+;;;; See also x86-vm for commentary on signed vs unsigned.
+
+(define-alien-routine ("os_context_pc_addr" context-pc-addr) (* unsigned-int)
+  (context (* os-context-t)))
+
+(defun context-pc (context)
+  (declare (type (alien (* os-context-t)) context))
+  (int-sap (deref (context-pc-addr context))))
+
+(define-alien-routine ("os_context_register_addr" context-register-addr)
+  (* unsigned-int)
+  (context (* os-context-t))
+  (index int))
+
+;;; FIXME: Should this and CONTEXT-PC be INLINE to reduce consing?
+;;; (Are they used in anything time-critical, or just the debugger?)
+(defun context-register (context index)
+  (declare (type (alien (* os-context-t)) context))
+  (deref (context-register-addr context index)))
+
+(defun %set-context-register (context index new)
+(declare (type (alien (* os-context-t)) context))
+(setf (deref (context-register-addr context index))
+      new))
+
+;;; This is like CONTEXT-REGISTER, but returns the value of a float
+;;; register. FORMAT is the type of float to return.
+
+;;; FIXME: Whether COERCE actually knows how to make a float out of a
+;;; long is another question. This stuff still needs testing.
+#+nil
+(define-alien-routine ("os_context_float_register_addr" context-float-register-addr)
+  (* long)
+  (context (* os-context-t))
+  (index int))
+#+nil
+(defun context-float-register (context index format)
+  (declare (type (alien (* os-context-t)) context))
+  (coerce (deref (context-float-register-addr context index)) format))
+#+nil
+(defun %set-context-float-register (context index format new)
+  (declare (type (alien (* os-context-t)) context))
+  (setf (deref (context-float-register-addr context index))
+        (coerce new format)))
+
+;;; Given a signal context, return the floating point modes word in
+;;; the same format as returned by FLOATING-POINT-MODES.
+(defun context-floating-point-modes (context)
+  ;; FIXME: As of sbcl-0.6.7 and the big rewrite of signal handling for
+  ;; POSIXness and (at the Lisp level) opaque signal contexts,
+  ;; this is stubified. It needs to be rewritten as an
+  ;; alien function.
+  (warn "stub CONTEXT-FLOATING-POINT-MODES")
+  ;; old code for Linux:
+  #+nil
+  (let ((cw (slot (deref (slot context 'fpstate) 0) 'cw))
+       (sw (slot (deref (slot context 'fpstate) 0) 'sw)))
+    ;;(format t "cw = ~4X~%sw = ~4X~%" cw sw)
+    ;; NOT TESTED -- Clear sticky bits to clear interrupt condition.
+    (setf (slot (deref (slot context 'fpstate) 0) 'sw) (logandc2 sw #x3f))
+    ;;(format t "new sw = ~X~%" (slot (deref (slot context 'fpstate) 0) 'sw))
+    ;; Simulate floating-point-modes VOP.
+    (logior (ash (logand sw #xffff) 16) (logxor (logand cw #xffff) #x3f)))
+
+  0)
+\f
+;;;; INTERNAL-ERROR-ARGS.
+
+;;; Given a (POSIX) signal context, extract the internal error
+;;; arguments from the instruction stream.  This is e.g.
+;;; 4       23      254     240     2       0       0       0 
+;;; |       ~~~~~~~~~~~~~~~~~~~~~~~~~
+;;; length         data              (everything is an octet)
+;;;  (pc)
+(defun internal-error-args (context)
+  (declare (type (alien (* os-context-t)) context))
+  (sb!int::/show0 "entering INTERNAL-ERROR-ARGS")
+  (let* ((pc (context-pc context))
+        (bad-inst (sap-ref-32 pc 0))
+        (op (ldb (byte 2 30) bad-inst))
+        (op2 (ldb (byte 3 22) bad-inst))
+        (op3 (ldb (byte 6 19) bad-inst)))
+    (declare (type system-area-pointer pc))
+    (cond ((and (= op #b00) (= op2 #b000))
+          (args-for-unimp-inst context))
+         ((and (= op #b10) (= (ldb (byte 4 2) op3) #b1000))
+          (args-for-tagged-add-inst context bad-inst))
+         ((and (= op #b10) (= op3 #b111010))
+          (args-for-tcc-inst bad-inst))
+         (t
+          (values #.(error-number-or-lose 'unknown-error) nil)))))
+
+(defun args-for-unimp-inst (context)
+  (declare (type (alien (* os-context-t)) context))
+  (let* ((pc (context-pc context))
+        (length (sap-ref-8 pc 4))
+        (vector (make-array length :element-type '(unsigned-byte 8))))
+    (declare (type system-area-pointer pc)
+            (type (unsigned-byte 8) length)
+            (type (simple-array (unsigned-byte 8) (*)) vector))
+    (copy-from-system-area pc (* n-byte-bits 5)
+                          vector (* n-word-bits
+                                    vector-data-offset)
+                          (* length n-byte-bits))
+    (let* ((index 0)
+          (error-number (sb!c::read-var-integer vector index)))
+      (collect ((sc-offsets))
+              (loop
+               (when (>= index length)
+                 (return))
+               (sc-offsets (sb!c::read-var-integer vector index)))
+              (values error-number (sc-offsets))))))
+
+(defun args-for-tagged-add-inst (context bad-inst)
+  (declare (type (alien (* os-context-t)) context))
+  (let* ((rs1 (ldb (byte 5 14) bad-inst))
+        (op1 (sb!kernel:make-lisp-obj (context-register context rs1))))
+    (if (fixnump op1)
+       (if (zerop (ldb (byte 1 13) bad-inst))
+           (let* ((rs2 (ldb (byte 5 0) bad-inst))
+                  (op2 (sb!kernel:make-lisp-obj (context-register context rs2))))
+             (if (fixnump op2)
+                 (values #.(error-number-or-lose 'unknown-error) nil)
+                 (values #.(error-number-or-lose 'object-not-fixnum-error)
+                         (list (sb!c::make-sc-offset
+                                descriptor-reg-sc-number
+                                rs2)))))
+           (values #.(error-number-or-lose 'unknown-error) nil))
+       (values #.(error-number-or-lose 'object-not-fixnum-error)
+               (list (sb!c::make-sc-offset descriptor-reg-sc-number
+                                           rs1))))))
+
+(defun args-for-tcc-inst (bad-inst)
+  (let* ((trap-number (ldb (byte 8 0) bad-inst))
+        (reg (ldb (byte 5 8) bad-inst)))
+    (values (case trap-number
+             (#.object-not-list-trap
+              #.(error-number-or-lose 'object-not-list-error))
+             (#.object-not-instance-trap
+              #.(error-number-or-lose 'object-not-instance-error))
+             (t
+              #.(error-number-or-lose 'unknown-error)))
+           (list (sb!c::make-sc-offset descriptor-reg-sc-number reg)))))
+
+\f
+;;; Do whatever is necessary to make the given code component
+;;; executable.  On the sparc, we don't need to do anything, because
+;;; the i and d caches are unified.
+(defun sanctify-for-execution (component)
+  (declare (ignore component))
+  nil)
index e5b5761..52f01c3 100644 (file)
           ;; boxing.
           (rehash-threshold (float rehash-threshold 1.0))
           (size+1 (1+ size))           ; The first element is not usable.
           ;; boxing.
           (rehash-threshold (float rehash-threshold 1.0))
           (size+1 (1+ size))           ; The first element is not usable.
-          (scaled-size (round (/ (float size+1) rehash-threshold)))
+           ;; KLUDGE: The most natural way of expressing the below is
+           ;; (round (/ (float size+1) rehash-threshold)), and indeed
+           ;; it was expressed like that until 0.7.0. However,
+           ;; MAKE-HASH-TABLE is called very early in cold-init, and
+           ;; the SPARC has no primitive instructions for rounding,
+           ;; but only for truncating; therefore, we fudge this issue
+           ;; a little. The other uses of truncate, below, similarly
+           ;; used to be round. -- CSR, 2002-10-01
+          ;;
+          ;; Note that this has not yet been audited for
+          ;; correctness. It just seems to work. -- CSR, 2002-11-02
+          (scaled-size (truncate (/ (float size+1) rehash-threshold)))
           (length (almost-primify (max scaled-size
                                        (1+ +min-hash-table-size+))))
           (index-vector (make-array length
           (length (almost-primify (max scaled-size
                                        (1+ +min-hash-table-size+))))
           (index-vector (make-array length
              (fixnum
               (+ rehash-size old-size))
              (float
              (fixnum
               (+ rehash-size old-size))
              (float
-              (the index (round (* rehash-size old-size)))))))
+              (the index (truncate (* rehash-size old-size)))))))
         (new-kv-vector (make-array (* 2 new-size)
                                    :initial-element +empty-ht-slot+))
         (new-next-vector (make-array new-size
         (new-kv-vector (make-array (* 2 new-size)
                                    :initial-element +empty-ht-slot+))
         (new-next-vector (make-array new-size
                                        :initial-element #x80000000)))
         (old-index-vector (hash-table-index-vector table))
         (new-length (almost-primify
                                        :initial-element #x80000000)))
         (old-index-vector (hash-table-index-vector table))
         (new-length (almost-primify
-                     (round (/ (float new-size)
+                     (truncate (/ (float new-size)
                                (hash-table-rehash-threshold table)))))
         (new-index-vector (make-array new-length
                                       :element-type '(unsigned-byte 32)
                                (hash-table-rehash-threshold table)))))
         (new-index-vector (make-array new-length
                                       :element-type '(unsigned-byte 32)
index 05c7539..9997616 100644 (file)
 \f
 ;;;; general warm init compilation policy
 
 \f
 ;;;; general warm init compilation policy
 
+;;; Without generational GC, GC gets really slow unless we collect in
+;;; large chunks. For small chunks, efficiency tends to grow roughly
+;;; linearly with chunk size. Later we hit diminishing returns as we
+;;; approach the total amount of RAM we use, or we can even get into
+;;; performance trouble by clobbering cache and VM systems too hard.
+;;; But modern machines tend to think of 20 Mb as a moderate amount of
+;;; memory, and it's of the same order of magnitude as the amount of
+;;; RAM we need for the build, so it seems like a plausible chunk size.
+#-gencgc
+(progn
+  (sb!ext:gc-off)
+  (setf (sb!ext:bytes-consed-between-gcs) (* 20 (expt 10 6)))
+  (sb!ext:gc-on))
+
 (proclaim '(optimize (compilation-speed 1)
                     (debug #+sb-show 2 #-sb-show 1)
                     (inhibit-warnings 2)
 (proclaim '(optimize (compilation-speed 1)
                     (debug #+sb-show 2 #-sb-show 1)
                     (inhibit-warnings 2)
index d2a98d5..85f2b1a 100644 (file)
@@ -68,7 +68,6 @@
 
 (defknown alien-funcall (alien-value &rest *) *
   (any recursive))
 
 (defknown alien-funcall (alien-value &rest *) *
   (any recursive))
-(defknown %alien-funcall (system-area-pointer alien-type &rest *) *)
 \f
 ;;;; cosmetic transforms
 
 \f
 ;;;; cosmetic transforms
 
index 183e2b1..4e940e2 100644 (file)
            (t
             (sub-dump-object obj file))))))
 
            (t
             (sub-dump-object obj file))))))
 
+;;; In the grand scheme of things I don't pretend to understand any
+;;; more how this works, or indeed whether.  But to write out specialized
+;;; vectors in the same format as fop-int-vector expects to read them
+;;; we need to be target-endian.  dump-integer-as-n-bytes always writes
+;;; little-endian (which is correct for all other integers) so for a bigendian
+;;; target we need to swap octets -- CSR, after DB
+
+(defun octet-swap (word bits)
+  "BITS must be a multiple of 8"
+  (do ((input word (ash input -8))
+       (output 0 (logior (ash output 8) (logand input #xff)))
+       (bits bits (- bits 8)))
+      ((<= bits 0) output)))
+
 (defun dump-i-vector (vec file &key data-only)
   (declare (type (simple-array * (*)) vec))
   (let ((len (length vec)))
 (defun dump-i-vector (vec file &key data-only)
   (declare (type (simple-array * (*)) vec))
   (let ((len (length vec)))
                      (multiple-value-bind (floor rem) (floor size 8)
                        (aver (zerop rem))
                        (dovector (i vec)
                      (multiple-value-bind (floor rem) (floor size 8)
                        (aver (zerop rem))
                        (dovector (i vec)
-                         (dump-integer-as-n-bytes i floor file))))
+                         (dump-integer-as-n-bytes
+                          (ecase sb!c:*backend-byte-order*
+                            (:little-endian i)
+                            (:big-endian (octet-swap i size)))
+                          floor file))))
                     (t ; harder cases, not supported in cross-compiler
                      (dump-raw-bytes vec bytes file))))
             (dump-signed-vector (size bytes)
                     (t ; harder cases, not supported in cross-compiler
                      (dump-raw-bytes vec bytes file))))
             (dump-signed-vector (size bytes)
diff --git a/src/compiler/early-aliencomp.lisp b/src/compiler/early-aliencomp.lisp
new file mode 100644 (file)
index 0000000..d19ce05
--- /dev/null
@@ -0,0 +1,3 @@
+(in-package "SB!C")
+
+(defknown %alien-funcall (system-area-pointer alien-type &rest *) *)
index 93ea581..bbd2b84 100644 (file)
             (n)
             (let* ((name (intern (format nil "BYTE-VECTOR-REF-~A" n)))
                    (number-octets (/ n 8))
             (n)
             (let* ((name (intern (format nil "BYTE-VECTOR-REF-~A" n)))
                    (number-octets (/ n 8))
-                   (ash-list
+                   (ash-list-le
                     (loop for i from 0 to (1- number-octets)
                           collect `(ash (aref byte-vector (+ byte-index ,i))
                                         ,(* i 8))))
                     (loop for i from 0 to (1- number-octets)
                           collect `(ash (aref byte-vector (+ byte-index ,i))
                                         ,(* i 8))))
-                   (setf-list
+                  (ash-list-be
+                   (loop for i from 0 to (1- number-octets)
+                         collect `(ash (aref byte-vector (+ byte-index
+                                                          ,(- number-octets 1 i)))
+                                       ,(* i 8))))
+                   (setf-list-le
                     (loop for i from 0 to (1- number-octets)
                           append
                           `((aref byte-vector (+ byte-index ,i))
                     (loop for i from 0 to (1- number-octets)
                           append
                           `((aref byte-vector (+ byte-index ,i))
-                            (ldb (byte 8 ,(* i 8)) new-value)))))
+                            (ldb (byte 8 ,(* i 8)) new-value))))
+                  (setf-list-be
+                   (loop for i from 0 to (1- number-octets)
+                          append
+                         `((aref byte-vector (+ byte-index ,i))
+                           (ldb (byte 8 ,(- n 8 (* i 8))) new-value)))))
               `(progn
                  (defun ,name (byte-vector byte-index)
               `(progn
                  (defun ,name (byte-vector byte-index)
-  (aver (= sb!vm:n-word-bits 32))
-  (aver (= sb!vm:n-byte-bits 8))
-  (ecase sb!c:*backend-byte-order*
-    (:little-endian
-                      (logior ,@ash-list))
-    (:big-endian
-     (error "stub: no big-endian ports of SBCL (yet?)"))))
-                 (defun (setf ,name) (new-value byte-vector byte-index)
-  (aver (= sb!vm:n-word-bits 32))
-  (aver (= sb!vm:n-byte-bits 8))
-  (ecase sb!c:*backend-byte-order*
-    (:little-endian
-                      (setf ,@setf-list))
-    (:big-endian
-                      (error "stub: no big-endian ports of SBCL (yet?)"))))))))
+                  (aver (= sb!vm:n-word-bits 32))
+                  (aver (= sb!vm:n-byte-bits 8))
+                  (logior ,@(ecase sb!c:*backend-byte-order*
+                                   (:little-endian ash-list-le)
+                                   (:big-endian ash-list-be))))
+               (defun (setf ,name) (new-value byte-vector byte-index)
+                 (aver (= sb!vm:n-word-bits 32))
+                 (aver (= sb!vm:n-byte-bits 8))
+                 (setf ,@(ecase sb!c:*backend-byte-order*
+                                (:little-endian setf-list-le)
+                                (:big-endian setf-list-be))))))))
   (make-byte-vector-ref-n 8)
   (make-byte-vector-ref-n 16)
   (make-byte-vector-ref-n 32))
   (make-byte-vector-ref-n 8)
   (make-byte-vector-ref-n 16)
   (make-byte-vector-ref-n 32))
                 (ldb (byte 8 0) value)
                 (byte-vector-ref-8 gspace-bytes (1+ gspace-byte-offset))
                 (ldb (byte 8 8) value)))))
                 (ldb (byte 8 0) value)
                 (byte-vector-ref-8 gspace-bytes (1+ gspace-byte-offset))
                 (ldb (byte 8 8) value)))))
+      (:sparc
+       (ecase kind
+        (:call
+         (error "Can't deal with call fixups yet."))
+        (:sethi
+         (setf (byte-vector-ref-32 gspace-bytes gspace-byte-offset)
+               (dpb (ldb (byte 22 10) value)
+                    (byte 22 0)
+                    (byte-vector-ref-32 gspace-bytes gspace-byte-offset))))
+        (:add
+         (setf (byte-vector-ref-32 gspace-bytes gspace-byte-offset)
+               (dpb (ldb (byte 10 0) value)
+                    (byte 10 0)
+                    (byte-vector-ref-32 gspace-bytes gspace-byte-offset))))))
       (:x86
        (let* ((un-fixed-up (byte-vector-ref-32 gspace-bytes
                                               gspace-byte-offset))
       (:x86
        (let* ((un-fixed-up (byte-vector-ref-32 gspace-bytes
                                               gspace-byte-offset))
@@ -2970,7 +2990,8 @@ initially undefined function references:~2%")
                                     sb!vm:static-space-start))
           (*dynamic*   (make-gspace :dynamic
                                     dynamic-space-id
                                     sb!vm:static-space-start))
           (*dynamic*   (make-gspace :dynamic
                                     dynamic-space-id
-                                    sb!vm:dynamic-space-start))
+                                    #!+gencgc sb!vm:dynamic-space-start
+                                    #!-gencgc sb!vm:dynamic-0-space-start))
           (*nil-descriptor* (make-nil-descriptor))
           (*current-reversed-cold-toplevels* *nil-descriptor*)
           (*unbound-marker* (make-other-immediate-descriptor
           (*nil-descriptor* (make-nil-descriptor))
           (*current-reversed-cold-toplevels* *nil-descriptor*)
           (*unbound-marker* (make-other-immediate-descriptor
diff --git a/src/compiler/sparc/alloc.lisp b/src/compiler/sparc/alloc.lisp
new file mode 100644 (file)
index 0000000..a67f6eb
--- /dev/null
@@ -0,0 +1,189 @@
+;;;; allocation VOPs for the Sparc port
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; LIST and LIST*
+
+(define-vop (list-or-list*)
+  (:args (things :more t))
+  (:temporary (:scs (descriptor-reg) :type list) ptr)
+  (:temporary (:scs (descriptor-reg)) temp)
+  (:temporary (:scs (descriptor-reg) :type list :to (:result 0) :target result)
+             res)
+  (:info num)
+  (:results (result :scs (descriptor-reg)))
+  (:variant-vars star)
+  (:policy :safe)
+  (:generator 0
+    (cond ((zerop num)
+          (move result null-tn))
+         ((and star (= num 1))
+          (move result (tn-ref-tn things)))
+         (t
+          (macrolet
+              ((maybe-load (tn)
+                 (once-only ((tn tn))
+                   `(sc-case ,tn
+                      ((any-reg descriptor-reg zero null)
+                       ,tn)
+                      (control-stack
+                       (load-stack-tn temp ,tn)
+                       temp)))))
+            (let* ((cons-cells (if star (1- num) num))
+                   (alloc (* (pad-data-block cons-size) cons-cells)))
+              (pseudo-atomic (:extra alloc)
+                (inst andn res alloc-tn lowtag-mask)
+                (inst or res list-pointer-lowtag)
+                (move ptr res)
+                (dotimes (i (1- cons-cells))
+                  (storew (maybe-load (tn-ref-tn things)) ptr
+                          cons-car-slot list-pointer-lowtag)
+                  (setf things (tn-ref-across things))
+                  (inst add ptr ptr (pad-data-block cons-size))
+                  (storew ptr ptr
+                          (- cons-cdr-slot cons-size)
+                          list-pointer-lowtag))
+                (storew (maybe-load (tn-ref-tn things)) ptr
+                        cons-car-slot list-pointer-lowtag)
+                (storew (if star
+                            (maybe-load (tn-ref-tn (tn-ref-across things)))
+                            null-tn)
+                        ptr cons-cdr-slot list-pointer-lowtag))
+              (move result res)))))))
+
+(define-vop (list list-or-list*)
+  (:variant nil))
+
+(define-vop (list* list-or-list*)
+  (:variant t))
+
+\f
+;;;; Special purpose inline allocators.
+
+(define-vop (allocate-code-object)
+  (:args (boxed-arg :scs (any-reg))
+        (unboxed-arg :scs (any-reg)))
+  (:results (result :scs (descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) ndescr)
+  (:temporary (:scs (any-reg) :from (:argument 0)) boxed)
+  (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) unboxed)
+  (:generator 100
+    (inst add boxed boxed-arg (fixnumize (1+ code-trace-table-offset-slot)))
+    (inst and boxed (lognot lowtag-mask))
+    (inst srl unboxed unboxed-arg word-shift)
+    (inst add unboxed lowtag-mask)
+    (inst and unboxed (lognot lowtag-mask))
+    (pseudo-atomic ()
+      ;; CMUCL Comment:
+      ;; Note: we don't have to subtract off the 4 that was added by
+      ;; pseudo-atomic, because oring in other-pointer-lowtag just adds
+      ;; it right back.
+      ;;
+      ;; This looks like another dreadful type pun. CSR - 2002-02-06
+      (inst or result alloc-tn other-pointer-lowtag)
+      (inst add alloc-tn boxed)
+      (inst add alloc-tn unboxed)
+      (inst sll ndescr boxed (- n-widetag-bits word-shift))
+      (inst or ndescr code-header-widetag)
+      (storew ndescr result 0 other-pointer-lowtag)
+      (storew unboxed result code-code-size-slot other-pointer-lowtag)
+      (storew null-tn result code-entry-points-slot other-pointer-lowtag)
+      (storew null-tn result code-debug-info-slot other-pointer-lowtag))))
+
+(define-vop (make-fdefn)
+  (:args (name :scs (descriptor-reg) :to :eval))
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:results (result :scs (descriptor-reg) :from :argument))
+  (:policy :fast-safe)
+  (:translate make-fdefn)
+  (:generator 37
+    (with-fixed-allocation (result temp fdefn-widetag fdefn-size)
+      (inst li temp (make-fixup (extern-alien-name "undefined_tramp") :foreign))
+      (storew name result fdefn-name-slot other-pointer-lowtag)
+      (storew null-tn result fdefn-fun-slot other-pointer-lowtag)
+      (storew temp result fdefn-raw-addr-slot other-pointer-lowtag))))
+
+
+(define-vop (make-closure)
+  (:args (function :to :save :scs (descriptor-reg)))
+  (:info length)
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:results (result :scs (descriptor-reg)))
+  (:generator 10
+    (let ((size (+ length closure-info-offset)))
+      (pseudo-atomic (:extra (pad-data-block size))
+       (inst andn result alloc-tn lowtag-mask)
+       (inst or result fun-pointer-lowtag)
+       (inst li temp (logior (ash (1- size) n-widetag-bits) closure-header-widetag))
+       (storew temp result 0 fun-pointer-lowtag)))
+    (storew function result closure-fun-slot fun-pointer-lowtag)))
+
+;;; The compiler likes to be able to directly make value cells.
+;;; 
+(define-vop (make-value-cell)
+  (:args (value :to :save :scs (descriptor-reg any-reg)))
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:results (result :scs (descriptor-reg)))
+  (:generator 10
+    (with-fixed-allocation
+       (result temp value-cell-header-widetag value-cell-size))
+    (storew value result value-cell-value-slot other-pointer-lowtag)))
+
+
+\f
+;;;; Automatic allocators for primitive objects.
+
+(define-vop (make-unbound-marker)
+  (:args)
+  (:results (result :scs (any-reg)))
+  (:generator 1
+    (inst li result unbound-marker-widetag)))
+
+(define-vop (fixed-alloc)
+  (:args)
+  (:info name words type lowtag)
+  (:ignore name)
+  (:results (result :scs (descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:generator 4
+    (pseudo-atomic (:extra (pad-data-block words))
+      (cond ((logbitp (1- n-lowtag-bits) lowtag)
+            (inst or result alloc-tn lowtag))
+           (t
+            (inst andn result alloc-tn lowtag-mask)
+            (inst or result lowtag)))
+      (when type
+       (inst li temp (logior (ash (1- words) n-widetag-bits) type))
+       (storew temp result 0 lowtag)))))
+
+(define-vop (var-alloc)
+  (:args (extra :scs (any-reg)))
+  (:arg-types positive-fixnum)
+  (:info name words type lowtag)
+  (:ignore name)
+  (:results (result :scs (descriptor-reg)))
+  (:temporary (:scs (any-reg)) bytes header)
+  (:generator 6
+    (inst add bytes extra (* (1+ words) n-word-bytes))
+    (inst sll header bytes (- n-widetag-bits 2))
+    (inst add header header (+ (ash -2 n-widetag-bits) type))
+    (inst and bytes (lognot lowtag-mask))
+    (pseudo-atomic ()
+      ;; Need to be careful if the lowtag and the pseudo-atomic flag
+      ;; are not compatible.
+      (cond ((logbitp (1- n-lowtag-bits) lowtag)
+            (inst or result alloc-tn lowtag))
+           (t
+            (inst andn result alloc-tn lowtag-mask)
+            (inst or result lowtag)))
+      (storew header result 0 lowtag)
+      (inst add alloc-tn alloc-tn bytes))))
diff --git a/src/compiler/sparc/arith.lisp b/src/compiler/sparc/arith.lisp
new file mode 100644 (file)
index 0000000..515f49e
--- /dev/null
@@ -0,0 +1,1251 @@
+;;;; the VM definition arithmetic VOPs for the Alpha
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; unary operations.
+
+(define-vop (fast-safe-arith-op)
+  (:policy :fast-safe)
+  (:effects)
+  (:affected))
+
+(define-vop (fixnum-unop fast-safe-arith-op)
+  (:args (x :scs (any-reg)))
+  (:results (res :scs (any-reg)))
+  (:note "inline fixnum arithmetic")
+  (:arg-types tagged-num)
+  (:result-types tagged-num))
+
+(define-vop (signed-unop fast-safe-arith-op)
+  (:args (x :scs (signed-reg)))
+  (:results (res :scs (signed-reg)))
+  (:note "inline (signed-byte 32) arithmetic")
+  (:arg-types signed-num)
+  (:result-types signed-num))
+
+(define-vop (fast-negate/fixnum fixnum-unop)
+  (:translate %negate)
+  (:generator 1
+    (inst neg res x)))
+
+(define-vop (fast-negate/signed signed-unop)
+  (:translate %negate)
+  (:generator 2
+    (inst neg res x)))
+
+(define-vop (fast-lognot/fixnum fixnum-unop)
+  (:translate lognot)
+  (:generator 2
+    (inst xor res x (fixnumize -1))))
+
+(define-vop (fast-lognot/signed signed-unop)
+  (:translate lognot)
+  (:generator 1
+    (inst not res x)))
+\f
+;;;; Binary fixnum operations.
+
+;;; Assume that any constant operand is the second arg...
+
+(define-vop (fast-fixnum-binop fast-safe-arith-op)
+  (:args (x :target r :scs (any-reg zero))
+        (y :target r :scs (any-reg zero)))
+  (:arg-types tagged-num tagged-num)
+  (:results (r :scs (any-reg)))
+  (:result-types tagged-num)
+  (:note "inline fixnum arithmetic"))
+
+(define-vop (fast-unsigned-binop fast-safe-arith-op)
+  (:args (x :target r :scs (unsigned-reg zero))
+        (y :target r :scs (unsigned-reg zero)))
+  (:arg-types unsigned-num unsigned-num)
+  (:results (r :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:note "inline (unsigned-byte 32) arithmetic"))
+
+(define-vop (fast-signed-binop fast-safe-arith-op)
+  (:args (x :target r :scs (signed-reg zero))
+        (y :target r :scs (signed-reg zero)))
+  (:arg-types signed-num signed-num)
+  (:results (r :scs (signed-reg)))
+  (:result-types signed-num)
+  (:note "inline (signed-byte 32) arithmetic"))
+
+
+(define-vop (fast-fixnum-binop-c fast-safe-arith-op)
+  (:args (x :target r :scs (any-reg zero)))
+  (:info y)
+  (:arg-types tagged-num
+             (:constant (and (signed-byte 11) (not (integer 0 0)))))
+  (:results (r :scs (any-reg)))
+  (:result-types tagged-num)
+  (:note "inline fixnum arithmetic"))
+
+(define-vop (fast-unsigned-binop-c fast-safe-arith-op)
+  (:args (x :target r :scs (unsigned-reg zero)))
+  (:info y)
+  (:arg-types unsigned-num
+             (:constant (and (signed-byte 13) (not (integer 0 0)))))
+  (:results (r :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:note "inline (unsigned-byte 32) arithmetic"))
+
+(define-vop (fast-signed-binop-c fast-safe-arith-op)
+  (:args (x :target r :scs (signed-reg zero)))
+  (:info y)
+  (:arg-types signed-num
+             (:constant (and (signed-byte 13) (not (integer 0 0)))))
+  (:results (r :scs (signed-reg)))
+  (:result-types signed-num)
+  (:note "inline (signed-byte 32) arithmetic"))
+
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+
+(defmacro define-binop (translate untagged-penalty op)
+  `(progn
+     (define-vop (,(symbolicate "FAST-" translate "/FIXNUM=>FIXNUM")
+                 fast-fixnum-binop)
+       (:translate ,translate)
+       (:generator 2
+        (inst ,op r x y)))
+     (define-vop (,(symbolicate 'fast- translate '-c/fixnum=>fixnum)
+                 fast-fixnum-binop-c)
+       (:translate ,translate)
+       (:generator 1
+        (inst ,op r x (fixnumize y))))
+     (define-vop (,(symbolicate "FAST-" translate "/SIGNED=>SIGNED")
+                 fast-signed-binop)
+       (:translate ,translate)
+       (:generator ,(1+ untagged-penalty)
+        (inst ,op r x y)))
+     (define-vop (,(symbolicate 'fast- translate '-c/signed=>signed)
+                 fast-signed-binop-c)
+       (:translate ,translate)
+       (:generator ,untagged-penalty
+        (inst ,op r x y)))
+     (define-vop (,(symbolicate "FAST-" translate "/UNSIGNED=>UNSIGNED")
+                 fast-unsigned-binop)
+       (:translate ,translate)
+       (:generator ,(1+ untagged-penalty)
+        (inst ,op r x y)))
+     (define-vop (,(symbolicate 'fast- translate '-c/unsigned=>unsigned)
+                 fast-unsigned-binop-c)
+       (:translate ,translate)
+       (:generator ,untagged-penalty
+        (inst ,op r x y)))))
+
+); eval-when
+
+(define-binop + 4 add)
+(define-binop - 4 sub)
+(define-binop logand 2 and)
+(define-binop logandc2 2 andn)
+(define-binop logior 2 or)
+(define-binop logorc2 2 orn)
+(define-binop logxor 2 xor)
+(define-binop logeqv 2 xnor)
+
+;;; Special logand cases: (logand signed unsigned) => unsigned
+
+(define-vop (fast-logand/signed-unsigned=>unsigned
+            fast-logand/unsigned=>unsigned)
+    (:args (x :target r :scs (signed-reg))
+          (y :scs (unsigned-reg unsigned-stack)))
+  (:arg-types signed-num unsigned-num))
+
+(define-vop (fast-logand/unsigned-signed=>unsigned
+            fast-logand/unsigned=>unsigned)
+    (:args (x :target r :scs (unsigned-reg))
+          (y :scs (signed-reg signed-stack)))
+  (:arg-types unsigned-num signed-num))
+    
+;;; Special case fixnum + and - that trap on overflow.  Useful when we
+;;; don't know that the output type is a fixnum.
+
+;;; I (toy@rtp.ericsson.se) took these out.  They don't seem to be
+;;; used anywhere at all.
+#+nil
+(progn
+(define-vop (+/fixnum fast-+/fixnum=>fixnum)
+  (:policy :safe)
+  (:results (r :scs (any-reg descriptor-reg)))
+  (:result-types tagged-num)
+  (:note "safe inline fixnum arithmetic")
+  (:generator 4
+    (inst taddcctv r x y)))
+
+(define-vop (+-c/fixnum fast-+-c/fixnum=>fixnum)
+  (:policy :safe)
+  (:results (r :scs (any-reg descriptor-reg)))
+  (:result-types tagged-num)
+  (:note "safe inline fixnum arithmetic")
+  (:generator 3
+    (inst taddcctv r x (fixnumize y))))
+
+(define-vop (-/fixnum fast--/fixnum=>fixnum)
+  (:policy :safe)
+  (:results (r :scs (any-reg descriptor-reg)))
+  (:result-types tagged-num)
+  (:note "safe inline fixnum arithmetic")
+  (:generator 4
+    (inst tsubcctv r x y)))
+
+(define-vop (--c/fixnum fast---c/fixnum=>fixnum)
+  (:policy :safe)
+  (:results (r :scs (any-reg descriptor-reg)))
+  (:result-types tagged-num)
+  (:note "safe inline fixnum arithmetic")
+  (:generator 3
+    (inst tsubcctv r x (fixnumize y))))
+
+)
+
+;;; Truncate
+
+;; This doesn't work for some reason.
+#+nil
+(define-vop (fast-v8-truncate/fixnum=>fixnum fast-safe-arith-op)
+  (:translate truncate)
+  (:args (x :scs (any-reg))
+        (y :scs (any-reg)))
+  (:arg-types tagged-num tagged-num)
+  (:results (quo :scs (any-reg))
+           (rem :scs (any-reg)))
+  (:result-types tagged-num tagged-num)
+  (:note "inline fixnum arithmetic")
+  (:temporary (:scs (any-reg) :target quo) q)
+  (:temporary (:scs (any-reg)) r)
+  (:temporary (:scs (signed-reg)) y-int)
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:guard #!+(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) t
+         #!-(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) nil)
+  (:generator 12
+    (let ((zero (generate-error-code vop division-by-zero-error x y)))
+      (inst cmp y zero-tn)
+      (inst b :eq zero)
+      ;; Extend the sign of X into the Y register
+        (inst sra r x 31)
+      (inst wry r)
+      ;; Remove tag bits so Q and R will be tagged correctly.
+      (inst sra y-int y fixnum-tag-bits)
+      (inst nop)
+      (inst nop)
+
+      (inst sdiv q x y-int)            ; Q is tagged.
+      ;; We have the quotient so we need to compute the remainder
+      (inst smul r q y-int)            ; R is tagged
+      (inst sub rem x r)
+      (unless (location= quo q)
+       (move quo q)))))
+
+(define-vop (fast-v8-truncate/signed=>signed fast-safe-arith-op)
+  (:translate truncate)
+  (:args (x :scs (signed-reg))
+        (y :scs (signed-reg)))
+  (:arg-types signed-num signed-num)
+  (:results (quo :scs (signed-reg))
+           (rem :scs (signed-reg)))
+  (:result-types signed-num signed-num)
+  (:note "inline (signed-byte 32) arithmetic")
+  (:temporary (:scs (signed-reg) :target quo) q)
+  (:temporary (:scs (signed-reg)) r)
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:guard #!+(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) t
+         #!-(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) nil)
+  (:generator 12
+    (let ((zero (generate-error-code vop division-by-zero-error x y)))
+      (inst cmp y zero-tn)
+      (inst b :eq zero #!+:sparc-v9 :pn)
+      ;; Extend the sign of X into the Y register
+        (inst sra r x 31)
+      (inst wry r)
+      (inst nop)
+      (inst nop)
+      (inst nop)
+
+      (inst sdiv q x y)
+      ;; We have the quotient so we need to compue the remainder
+      (inst smul r q y)                ; rem
+      (inst sub rem x r)
+      (unless (location= quo q)
+       (move quo q)))))
+
+(define-vop (fast-v8-truncate/unsigned=>unsigned fast-safe-arith-op)
+  (:translate truncate)
+  (:args (x :scs (unsigned-reg))
+        (y :scs (unsigned-reg)))
+  (:arg-types unsigned-num unsigned-num)
+  (:results (quo :scs (unsigned-reg))
+           (rem :scs (unsigned-reg)))
+  (:result-types unsigned-num unsigned-num)
+  (:note "inline (unsigned-byte 32) arithmetic")
+  (:temporary (:scs (unsigned-reg) :target quo) q)
+  (:temporary (:scs (unsigned-reg)) r)
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:guard #!+(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) t
+         #!-(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) nil)
+  (:generator 8
+    (let ((zero (generate-error-code vop division-by-zero-error x y)))
+      (inst cmp y zero-tn)
+      (inst b :eq zero #!+:sparc-v9 :pn)
+        (inst wry zero-tn)             ; Clear out high part
+      (inst nop)
+      (inst nop)
+      (inst nop)
+      
+      (inst udiv q x y)
+      ;; Compute remainder
+      (inst umul r q y)
+      (inst sub rem x r)
+      (unless (location= quo q)
+       (inst move quo q)))))
+
+#!+:sparc-v9
+(define-vop (fast-v9-truncate/signed=>signed fast-safe-arith-op)
+  (:translate truncate)
+  (:args (x :scs (signed-reg))
+        (y :scs (signed-reg)))
+  (:arg-types signed-num signed-num)
+  (:results (quo :scs (signed-reg))
+           (rem :scs (signed-reg)))
+  (:result-types signed-num signed-num)
+  (:note "inline (signed-byte 32) arithmetic")
+  (:temporary (:scs (signed-reg) :target quo) q)
+  (:temporary (:scs (signed-reg)) r)
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:guard #!+:sparc-64 t #!-:sparc-64 nil)
+  (:generator 8
+    (let ((zero (generate-error-code vop division-by-zero-error x y)))
+      (inst cmp y zero-tn)
+      (inst b :eq zero #!+:sparc-v9 :pn)
+      ;; Sign extend the numbers, just in case.
+        (inst sra x 0)
+      (inst sra y 0)
+      (inst sdivx q x y)
+      ;; Compute remainder
+      (inst mulx r q y)
+      (inst sub rem x r)
+      (unless (location= quo q)
+       (inst move quo q)))))
+
+(define-vop (fast-v9-truncate/unsigned=>unsigned fast-safe-arith-op)
+  (:translate truncate)
+  (:args (x :scs (unsigned-reg))
+        (y :scs (unsigned-reg)))
+  (:arg-types unsigned-num unsigned-num)
+  (:results (quo :scs (unsigned-reg))
+           (rem :scs (unsigned-reg)))
+  (:result-types unsigned-num unsigned-num)
+  (:note "inline (unsigned-byte 32) arithmetic")
+  (:temporary (:scs (unsigned-reg) :target quo) q)
+  (:temporary (:scs (unsigned-reg)) r)
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:guard #!+:sparc-64 t #!-:sparc-64 nil)
+  (:generator 8
+    (let ((zero (generate-error-code vop division-by-zero-error x y)))
+      (inst cmp y zero-tn)
+      (inst b :eq zero #!+:sparc-v9 :pn)
+      ;; Zap the higher 32 bits, just in case
+        (inst srl x 0)
+      (inst srl y 0)
+      (inst udivx q x y)
+      ;; Compute remainder
+      (inst mulx r q y)
+      (inst sub rem x r)
+      (unless (location= quo q)
+       (inst move quo q)))))
+
+;;; Shifting
+
+(macrolet
+    ((frob (name sc-type type shift-right-inst)
+       `(define-vop (,name)
+         (:note "inline ASH")
+         (:args (number :scs (,sc-type) :to :save)
+                (amount :scs (signed-reg immediate)))
+         (:arg-types ,type signed-num)
+         (:results (result :scs (,sc-type)))
+         (:result-types ,type)
+         (:translate ash)
+         (:policy :fast-safe)
+         (:temporary (:sc non-descriptor-reg) ndesc)
+         (:generator 5
+           (sc-case amount
+            #!+:sparc-v9
+            (signed-reg
+             (let ((done (gen-label))
+                   (positive (gen-label)))
+               (inst cmp amount)
+               (inst b :ge positive)
+               (inst neg ndesc amount)
+               ;; ndesc = max(-amount, 31)
+               (inst cmp ndesc 31)
+               (inst cmove :ge ndesc 31)
+               (inst b done)
+               (inst ,shift-right-inst result number ndesc)
+               (emit-label positive)
+               ;; The result-type assures us that this shift will not
+               ;; overflow.
+               (inst sll result number amount)
+               ;; We want a right shift of the appropriate size.
+               (emit-label done)))
+            #!-:sparc-v9
+            (signed-reg
+             (let ((positive (gen-label))
+                   (done (gen-label)))
+               (inst cmp amount)
+               (inst b :ge positive)
+               (inst neg ndesc amount)
+               (inst cmp ndesc 31)
+               (inst b :le done)
+               (inst ,shift-right-inst result number ndesc)
+               (inst b done)
+               (inst ,shift-right-inst result number 31)
+               
+               (emit-label positive)
+               ;; The result-type assures us that this shift will not overflow.
+               (inst sll result number amount)
+               
+               (emit-label done)))
+            (immediate
+             (let ((amount (tn-value amount)))
+               (if (minusp amount)
+                   (let ((amount (min 31 (- amount))))
+                     (inst ,shift-right-inst result number amount))
+                   (inst sll result number amount)))))))))
+  (frob fast-ash/signed=>signed signed-reg signed-num sra)
+  (frob fast-ash/unsigned=>unsigned unsigned-reg unsigned-num srl))
+
+;; Some special cases where we know we want a left shift.  Just do the
+;; shift, instead of checking for the sign of the shift.
+(macrolet
+    ((frob (name sc-type type result-type cost)
+       `(define-vop (,name)
+        (:note "inline ASH")
+        (:translate ash)
+        (:args (number :scs (,sc-type))
+               (amount :scs (signed-reg unsigned-reg immediate)))
+        (:arg-types ,type positive-fixnum)
+        (:results (result :scs (,result-type)))
+        (:result-types ,type)
+        (:policy :fast-safe)
+        (:generator ,cost
+         ;; The result-type assures us that this shift will not
+         ;; overflow. And for fixnum's, the zero bits that get
+         ;; shifted in are just fine for the fixnum tag.
+         (sc-case amount
+          ((signed-reg unsigned-reg)
+           (inst sll result number amount))
+          (immediate
+           (let ((amount (tn-value amount)))
+             (assert (>= amount 0))
+             (inst sll result number amount))))))))
+  (frob fast-ash-left/signed=>signed signed-reg signed-num signed-reg 3)
+  (frob fast-ash-left/fixnum=>fixnum any-reg tagged-num any-reg 2)
+  (frob fast-ash-left/unsigned=>unsigned unsigned-reg unsigned-num unsigned-reg 3))
+
+(defknown ash-right-signed ((signed-byte #.sb!vm:n-word-bits)
+                           (and fixnum unsigned-byte))
+  (signed-byte #.sb!vm:n-word-bits)
+  (movable foldable flushable))
+
+(defknown ash-right-unsigned ((unsigned-byte #.sb!vm:n-word-bits)
+                             (and fixnum unsigned-byte))
+  (unsigned-byte #.sb!vm:n-word-bits)
+  (movable foldable flushable))
+
+;; Some special cases where we want a right shift.  Just do the shift.
+;; (Needs appropriate deftransforms to call these, though.)
+
+(macrolet
+    ((frob (trans name sc-type type shift-inst cost)
+       `(define-vop (,name)
+        (:note "inline right ASH")
+        (:translate ,trans)
+        (:args (number :scs (,sc-type))
+               (amount :scs (signed-reg unsigned-reg immediate)))
+        (:arg-types ,type positive-fixnum)
+        (:results (result :scs (,sc-type)))
+        (:result-types ,type)
+        (:policy :fast-safe)
+        (:generator ,cost
+           (sc-case amount
+            ((signed-reg unsigned-reg)
+               (inst ,shift-inst result number amount))
+            (immediate
+             (let ((amt (tn-value amount)))
+               (inst ,shift-inst result number amt))))))))
+  (frob ash-right-signed fast-ash-right/signed=>signed
+       signed-reg signed-num sra 3)
+  (frob ash-right-unsigned fast-ash-right/unsigned=>unsigned
+       unsigned-reg unsigned-num srl 3))
+
+(define-vop (fast-ash-right/fixnum=>fixnum)
+    (:note "inline right ASH")
+  (:translate ash-right-signed)
+  (:args (number :scs (any-reg))
+        (amount :scs (signed-reg unsigned-reg immediate)))
+  (:arg-types tagged-num positive-fixnum)
+  (:results (result :scs (any-reg)))
+  (:result-types tagged-num)
+  (:temporary (:sc non-descriptor-reg :target result) temp)
+  (:policy :fast-safe)
+  (:generator 2
+    ;; Shift the fixnum right by the desired amount.  Then zap out the
+    ;; 2 LSBs to make it a fixnum again.  (Those bits are junk.)
+    (sc-case amount
+      ((signed-reg unsigned-reg)
+       (inst sra temp number amount))
+      (immediate
+       (inst sra temp number (tn-value amount))))
+    (inst andn result temp fixnum-tag-mask)))
+    
+
+
+\f
+(define-vop (signed-byte-32-len)
+  (:translate integer-length)
+  (:note "inline (signed-byte 32) integer-length")
+  (:policy :fast-safe)
+  (:args (arg :scs (signed-reg) :target shift))
+  (:arg-types signed-num)
+  (:results (res :scs (any-reg)))
+  (:result-types positive-fixnum)
+  (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) shift)
+  (:generator 30
+    (let ((loop (gen-label))
+         (test (gen-label)))
+      (inst addcc shift zero-tn arg)
+      (inst b :ge test)
+      (move res zero-tn)
+      (inst b test)
+      (inst not shift)
+
+      (emit-label loop)
+      (inst add res (fixnumize 1))
+      
+      (emit-label test)
+      (inst cmp shift)
+      (inst b :ne loop)
+      (inst srl shift 1))))
+
+(define-vop (unsigned-byte-32-count)
+  (:translate logcount)
+  (:note "inline (unsigned-byte 32) logcount")
+  (:policy :fast-safe)
+  (:args (arg :scs (unsigned-reg)))
+  (:arg-types unsigned-num)
+  (:results (res :scs (unsigned-reg)))
+  (:result-types positive-fixnum)
+  (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) mask temp)
+  (:generator 35
+      (move res arg)
+
+      (dolist (stuff '((1 #x55555555) (2 #x33333333) (4 #x0f0f0f0f)
+                      (8 #x00ff00ff) (16 #x0000ffff)))
+       (destructuring-bind (shift bit-mask)
+           stuff
+         ;; Set mask
+         (inst sethi mask (ldb (byte 22 10) bit-mask))
+         (inst add mask (ldb (byte 10 0) bit-mask))
+
+         (inst and temp res mask)
+         (inst srl res shift)
+         (inst and res mask)
+         (inst add res temp)))))
+
+
+;;; Multiply and Divide.
+
+(define-vop (fast-v8-*/fixnum=>fixnum fast-fixnum-binop)
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:translate *)
+  (:guard #!+(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) t
+         #!-(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) nil)
+  (:generator 2
+    ;; The cost here should be less than the cost for
+    ;; */signed=>signed.  Why?  A fixnum product using signed=>signed
+    ;; has to convert both args to signed-nums.  But using this, we
+    ;; don't have to and that saves an instruction.
+    (inst sra temp y fixnum-tag-bits)
+    (inst smul r x temp)))
+
+(define-vop (fast-v8-*/signed=>signed fast-signed-binop)
+  (:translate *)
+  (:guard #!+(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) t
+         #!-(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) nil)
+  (:generator 3
+    (inst smul r x y)))
+
+(define-vop (fast-v8-*/unsigned=>unsigned fast-unsigned-binop)
+  (:translate *)
+  (:guard #!+(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) t
+         #!-(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) nil)
+  (:generator 3
+    (inst umul r x y)))
+
+;; The smul and umul instructions are deprecated on the Sparc V9.  Use
+;; mulx instead.
+(define-vop (fast-v9-*/fixnum=>fixnum fast-fixnum-binop)
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:translate *)
+  (:guard #!+:sparc-64 t #!-:sparc-64 nil)
+  (:generator 4
+    (inst sra temp y fixnum-tag-bits)
+    (inst mulx r x temp)))
+
+(define-vop (fast-v9-*/signed=>signed fast-signed-binop)
+  (:translate *)
+  (:guard #!+:sparc-64 t #!-:sparc-64 nil)
+  (:generator 3
+    (inst mulx r x y)))
+
+(define-vop (fast-v9-*/unsigned=>unsigned fast-unsigned-binop)
+  (:translate *)
+  (:guard #!+:sparc-64 t #!-:sparc-64 nil)
+  (:generator 3
+    (inst mulx r x y)))
+
+\f
+;;;; Binary conditional VOPs:
+
+(define-vop (fast-conditional)
+  (:conditional)
+  (:info target not-p)
+  (:effects)
+  (:affected)
+  (:policy :fast-safe))
+
+(deftype integer-with-a-bite-out (s bite)
+  (cond ((eq s '*) 'integer)
+       ((and (integerp s) (> s 1))
+        (let ((bound (ash 1 (1- s))))
+          `(integer ,(- bound) ,(- bound bite 1))))
+       (t
+        (error "Bad size specified for SIGNED-BYTE type specifier: ~S." s))))
+
+(define-vop (fast-conditional/fixnum fast-conditional)
+  (:args (x :scs (any-reg zero))
+        (y :scs (any-reg zero)))
+  (:arg-types tagged-num tagged-num)
+  (:note "inline fixnum comparison"))
+
+(define-vop (fast-conditional-c/fixnum fast-conditional/fixnum)
+  (:args (x :scs (any-reg zero)))
+  (:arg-types tagged-num (:constant (signed-byte 11)))
+  (:info target not-p y))
+
+(define-vop (fast-conditional/signed fast-conditional)
+  (:args (x :scs (signed-reg zero))
+        (y :scs (signed-reg zero)))
+  (:arg-types signed-num signed-num)
+  (:note "inline (signed-byte 32) comparison"))
+
+(define-vop (fast-conditional-c/signed fast-conditional/signed)
+  (:args (x :scs (signed-reg zero)))
+  (:arg-types signed-num (:constant (signed-byte 13)))
+  (:info target not-p y))
+
+(define-vop (fast-conditional/unsigned fast-conditional)
+  (:args (x :scs (unsigned-reg zero))
+        (y :scs (unsigned-reg zero)))
+  (:arg-types unsigned-num unsigned-num)
+  (:note "inline (unsigned-byte 32) comparison"))
+
+(define-vop (fast-conditional-c/unsigned fast-conditional/unsigned)
+  (:args (x :scs (unsigned-reg zero)))
+  (:arg-types unsigned-num (:constant (unsigned-byte 12)))
+  (:info target not-p y))
+
+
+(defmacro define-conditional-vop (tran cond unsigned not-cond not-unsigned)
+  `(progn
+     ,@(mapcar (lambda (suffix cost signed)
+                (unless (and (member suffix '(/fixnum -c/fixnum))
+                             (eq tran 'eql))
+                  `(define-vop (,(intern (format nil "~:@(FAST-IF-~A~A~)"
+                                                 tran suffix))
+                                ,(intern
+                                  (format nil "~:@(FAST-CONDITIONAL~A~)"
+                                          suffix)))
+                    (:translate ,tran)
+                    (:generator ,cost
+                     (inst cmp x
+                      ,(if (eq suffix '-c/fixnum) '(fixnumize y) 'y))
+                     (inst b (if not-p
+                                 ,(if signed not-cond not-unsigned)
+                                 ,(if signed cond unsigned))
+                      target)
+                     (inst nop)))))
+              '(/fixnum -c/fixnum /signed -c/signed /unsigned -c/unsigned)
+              '(4 3 6 5 6 5)
+              '(t t t t nil nil))))
+
+(define-conditional-vop < :lt :ltu :ge :geu)
+
+(define-conditional-vop > :gt :gtu :le :leu)
+
+(define-conditional-vop eql :eq :eq :ne :ne)
+
+;;; EQL/FIXNUM is funny because the first arg can be of any type, not just a
+;;; known fixnum.
+
+;;; These versions specify a fixnum restriction on their first arg.  We have
+;;; also generic-eql/fixnum VOPs which are the same, but have no restriction on
+;;; the first arg and a higher cost.  The reason for doing this is to prevent
+;;; fixnum specific operations from being used on word integers, spuriously
+;;; consing the argument.
+;;;
+
+(define-vop (fast-eql/fixnum fast-conditional)
+  (:args (x :scs (any-reg descriptor-reg zero))
+        (y :scs (any-reg zero)))
+  (:arg-types tagged-num tagged-num)
+  (:note "inline fixnum comparison")
+  (:translate eql)
+  (:generator 4
+    (inst cmp x y)
+    (inst b (if not-p :ne :eq) target)
+    (inst nop)))
+;;;
+(define-vop (generic-eql/fixnum fast-eql/fixnum)
+  (:arg-types * tagged-num)
+  (:variant-cost 7))
+
+(define-vop (fast-eql-c/fixnum fast-conditional/fixnum)
+  (:args (x :scs (any-reg descriptor-reg zero)))
+  (:arg-types tagged-num (:constant (signed-byte 11)))
+  (:info target not-p y)
+  (:translate eql)
+  (:generator 2
+    (inst cmp x (fixnumize y))
+    (inst b (if not-p :ne :eq) target)
+    (inst nop)))
+;;;
+(define-vop (generic-eql-c/fixnum fast-eql-c/fixnum)
+  (:arg-types * (:constant (signed-byte 11)))
+  (:variant-cost 6))
+
+\f
+;;;; 32-bit logical operations
+
+(define-vop (merge-bits)
+  (:translate merge-bits)
+  (:args (shift :scs (signed-reg unsigned-reg))
+        (prev :scs (unsigned-reg))
+        (next :scs (unsigned-reg)))
+  (:arg-types tagged-num unsigned-num unsigned-num)
+  (:temporary (:scs (unsigned-reg) :to (:result 0)) temp)
+  (:temporary (:scs (unsigned-reg) :to (:result 0) :target result) res)
+  (:results (result :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:policy :fast-safe)
+  (:generator 4
+    (let ((done (gen-label)))
+      (inst cmp shift)
+      (inst b :eq done)
+      (inst srl res next shift)
+      (inst sub temp zero-tn shift)
+      (inst sll temp prev temp)
+      (inst or res temp)
+      (emit-label done)
+      (move result res))))
+
+
+(define-vop (32bit-logical)
+  (:args (x :scs (unsigned-reg zero))
+        (y :scs (unsigned-reg zero)))
+  (:arg-types unsigned-num unsigned-num)
+  (:results (r :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:policy :fast-safe))
+
+(define-vop (32bit-logical-not 32bit-logical)
+  (:translate 32bit-logical-not)
+  (:args (x :scs (unsigned-reg zero)))
+  (:arg-types unsigned-num)
+  (:generator 1
+    (inst not r x)))
+
+(define-vop (32bit-logical-and 32bit-logical)
+  (:translate 32bit-logical-and)
+  (:generator 1
+    (inst and r x y)))
+
+(deftransform 32bit-logical-nand ((x y) (* *))
+  '(32bit-logical-not (32bit-logical-and x y)))
+
+(define-vop (32bit-logical-or 32bit-logical)
+  (:translate 32bit-logical-or)
+  (:generator 1
+    (inst or r x y)))
+
+(deftransform 32bit-logical-nor ((x y) (* *))
+  '(32bit-logical-not (32bit-logical-or x y)))
+
+(define-vop (32bit-logical-xor 32bit-logical)
+  (:translate 32bit-logical-xor)
+  (:generator 1
+    (inst xor r x y)))
+
+(define-vop (32bit-logical-eqv 32bit-logical)
+  (:translate 32bit-logical-eqv)
+  (:generator 1
+    (inst xnor r x y)))
+
+(define-vop (32bit-logical-orc2 32bit-logical)
+  (:translate 32bit-logical-orc2)
+  (:generator 1
+    (inst orn r x y)))
+
+(deftransform 32bit-logical-orc1 ((x y) (* *))
+  '(32bit-logical-orc2 y x))
+
+(define-vop (32bit-logical-andc2 32bit-logical)
+  (:translate 32bit-logical-andc2)
+  (:generator 1
+    (inst andn r x y)))
+
+(deftransform 32bit-logical-andc1 ((x y) (* *))
+  '(32bit-logical-andc2 y x))
+
+
+(define-vop (shift-towards-someplace)
+  (:policy :fast-safe)
+  (:args (num :scs (unsigned-reg))
+        (amount :scs (signed-reg)))
+  (:arg-types unsigned-num tagged-num)
+  (:results (r :scs (unsigned-reg)))
+  (:result-types unsigned-num))
+
+(define-vop (shift-towards-start shift-towards-someplace)
+  (:translate shift-towards-start)
+  (:note "shift-towards-start")
+  (:generator 1
+    (inst sll r num amount)))
+
+(define-vop (shift-towards-end shift-towards-someplace)
+  (:translate shift-towards-end)
+  (:note "shift-towards-end")
+  (:generator 1
+    (inst srl r num amount)))
+
+
+
+\f
+;;;; Bignum stuff.
+
+(define-vop (bignum-length get-header-data)
+  (:translate sb!bignum::%bignum-length)
+  (:policy :fast-safe))
+
+(define-vop (bignum-set-length set-header-data)
+  (:translate sb!bignum::%bignum-set-length)
+  (:policy :fast-safe))
+
+(define-vop (bignum-ref word-index-ref)
+  (:variant bignum-digits-offset other-pointer-lowtag)
+  (:translate sb!bignum::%bignum-ref)
+  (:results (value :scs (unsigned-reg)))
+  (:result-types unsigned-num))
+
+(define-vop (bignum-set word-index-set)
+  (:variant bignum-digits-offset other-pointer-lowtag)
+  (:translate sb!bignum::%bignum-set)
+  (:args (object :scs (descriptor-reg))
+        (index :scs (any-reg immediate zero))
+        (value :scs (unsigned-reg)))
+  (:arg-types t positive-fixnum unsigned-num)
+  (:results (result :scs (unsigned-reg)))
+  (:result-types unsigned-num))
+
+(define-vop (digit-0-or-plus)
+  (:translate sb!bignum::%digit-0-or-plusp)
+  (:policy :fast-safe)
+  (:args (digit :scs (unsigned-reg)))
+  (:arg-types unsigned-num)
+  (:results (result :scs (descriptor-reg)))
+  (:guard #!-:sparc-v9 t #!+:sparc-v9 nil)
+  (:generator 3
+    (let ((done (gen-label)))
+      (inst cmp digit)
+      (inst b :lt done)
+      (move result null-tn)
+      (load-symbol result t)
+      (emit-label done))))
+
+(define-vop (v9-digit-0-or-plus-cmove)
+  (:translate sb!bignum::%digit-0-or-plusp)
+  (:policy :fast-safe)
+  (:args (digit :scs (unsigned-reg)))
+  (:arg-types unsigned-num)
+  (:results (result :scs (descriptor-reg)))
+  (:guard #!+:sparc-v9 t #!-:sparc-v9 nil)
+  (:generator 3
+    (inst cmp digit)
+    (load-symbol result t)
+    (inst cmove :lt result null-tn)))
+
+;; This doesn't work?
+#+nil
+(define-vop (v9-digit-0-or-plus-movr)
+  (:translate sb!bignum::%digit-0-or-plusp)
+  (:policy :fast-safe)
+  (:args (digit :scs (unsigned-reg)))
+  (:arg-types unsigned-num)
+  (:results (result :scs (descriptor-reg)))
+  (:temporary (:scs (descriptor-reg)) temp)
+  (:guard #!+:sparc-v9 t #!-:sparc-v9 nil)
+  (:generator 2
+    (load-symbol temp t)
+    (inst movr result null-tn digit :lz)
+    (inst movr result temp digit :gez)))
+
+
+(define-vop (add-w/carry)
+  (:translate sb!bignum::%add-with-carry)
+  (:policy :fast-safe)
+  (:args (a :scs (unsigned-reg))
+        (b :scs (unsigned-reg))
+        (c :scs (any-reg)))
+  (:arg-types unsigned-num unsigned-num positive-fixnum)
+  (:results (result :scs (unsigned-reg))
+           (carry :scs (unsigned-reg)))
+  (:result-types unsigned-num positive-fixnum)
+  (:generator 3
+    (inst addcc zero-tn c -1)
+    (inst addxcc result a b)
+    (inst addx carry zero-tn zero-tn)))
+
+(define-vop (sub-w/borrow)
+  (:translate sb!bignum::%subtract-with-borrow)
+  (:policy :fast-safe)
+  (:args (a :scs (unsigned-reg))
+        (b :scs (unsigned-reg))
+        (c :scs (any-reg)))
+  (:arg-types unsigned-num unsigned-num positive-fixnum)
+  (:results (result :scs (unsigned-reg))
+           (borrow :scs (unsigned-reg)))
+  (:result-types unsigned-num positive-fixnum)
+  (:generator 4
+    (inst subcc zero-tn c 1)
+    (inst subxcc result a b)
+    (inst addx borrow zero-tn zero-tn)
+    (inst xor borrow 1)))
+
+;;; EMIT-MULTIPLY -- This is used both for bignum stuff and in assembly
+;;; routines.
+;;; 
+(defun emit-multiply (multiplier multiplicand result-high result-low)
+  "Emit code to multiply MULTIPLIER with MULTIPLICAND, putting the result
+  in RESULT-HIGH and RESULT-LOW.  KIND is either :signed or :unsigned.
+  Note: the lifetimes of MULTIPLICAND and RESULT-HIGH overlap."
+  (declare (type tn multiplier result-high result-low)
+          (type (or tn (signed-byte 13)) multiplicand))
+  ;; It seems that emit-multiply is only used to do an unsigned
+  ;; multiply, so the code only does an unsigned multiply.
+  #!+:sparc-64
+  (progn
+    ;; Take advantage of V9's 64-bit multiplier.
+    ;;
+    ;; Make sure the multiplier and multiplicand are really
+    ;; unsigned 64-bit numbers.
+    (inst srl multiplier 0)
+    (inst srl multiplicand 0)
+  
+    ;; Multiply the two numbers and put the result in
+    ;; result-high.  Copy the low 32-bits to result-low.  Then
+    ;; shift result-high so the high 32-bits end up in the low
+    ;; 32-bits.
+    (inst mulx result-high multiplier multiplicand)
+    (inst move result-low result-high)
+    (inst srax result-high 32))
+  #!+(and (not :sparc-64) (or :sparc-v8 :sparc-v9))
+  (progn
+    ;; V8 has a multiply instruction.  This should also work for
+    ;; the V9, but umul and the Y register is deprecated on the
+    ;; V9.
+    (inst umul result-low multiplier multiplicand)
+    (inst rdy result-high))
+  #!+(and (not :sparc-64) (not (or :sparc-v8 :sparc-v9)))
+  (let ((label (gen-label)))
+    (inst wry multiplier)
+    (inst andcc result-high zero-tn)
+    ;; Note: we can't use the Y register until three insts
+    ;; after it's written.
+    (inst nop)
+    (inst nop)
+    (dotimes (i 32)
+      (inst mulscc result-high multiplicand))
+    (inst mulscc result-high zero-tn)
+    (inst cmp multiplicand)
+    (inst b :ge label)
+    (inst nop)
+    (inst add result-high multiplier)
+    (emit-label label)
+    (inst rdy result-low)))
+
+(define-vop (bignum-mult-and-add-3-arg)
+  (:translate sb!bignum::%multiply-and-add)
+  (:policy :fast-safe)
+  (:args (x :scs (unsigned-reg) :to (:eval 1))
+        (y :scs (unsigned-reg) :to (:eval 1))
+        (carry-in :scs (unsigned-reg) :to (:eval 2)))
+  (:arg-types unsigned-num unsigned-num unsigned-num)
+  (:results (hi :scs (unsigned-reg) :from (:eval 0))
+           (lo :scs (unsigned-reg) :from (:eval 1)))
+  (:result-types unsigned-num unsigned-num)
+  (:generator 40
+    (emit-multiply x y hi lo)
+    (inst addcc lo carry-in)
+    (inst addx hi zero-tn)))
+
+(define-vop (bignum-mult-and-add-4-arg)
+  (:translate sb!bignum::%multiply-and-add)
+  (:policy :fast-safe)
+  (:args (x :scs (unsigned-reg) :to (:eval 1))
+        (y :scs (unsigned-reg) :to (:eval 1))
+        (prev :scs (unsigned-reg) :to (:eval 2))
+        (carry-in :scs (unsigned-reg) :to (:eval 2)))
+  (:arg-types unsigned-num unsigned-num unsigned-num unsigned-num)
+  (:results (hi :scs (unsigned-reg) :from (:eval 0))
+           (lo :scs (unsigned-reg) :from (:eval 1)))
+  (:result-types unsigned-num unsigned-num)
+  (:generator 40
+    (emit-multiply x y hi lo)
+    (inst addcc lo carry-in)
+    (inst addx hi zero-tn)
+    (inst addcc lo prev)
+    (inst addx hi zero-tn)))
+
+(define-vop (bignum-mult)
+  (:translate sb!bignum::%multiply)
+  (:policy :fast-safe)
+  (:args (x :scs (unsigned-reg) :to (:result 1))
+        (y :scs (unsigned-reg) :to (:result 1)))
+  (:arg-types unsigned-num unsigned-num)
+  (:results (hi :scs (unsigned-reg))
+           (lo :scs (unsigned-reg)))
+  (:result-types unsigned-num unsigned-num)
+  (:generator 40
+    (emit-multiply x y hi lo)))
+
+(define-vop (bignum-lognot)
+  (:translate sb!bignum::%lognot)
+  (:policy :fast-safe)
+  (:args (x :scs (unsigned-reg)))
+  (:arg-types unsigned-num)
+  (:results (r :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:generator 1
+    (inst not r x)))
+
+(define-vop (fixnum-to-digit)
+  (:translate sb!bignum::%fixnum-to-digit)
+  (:policy :fast-safe)
+  (:args (fixnum :scs (any-reg)))
+  (:arg-types tagged-num)
+  (:results (digit :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:generator 1
+    (inst sra digit fixnum fixnum-tag-bits)))
+
+(define-vop (bignum-floor)
+  (:translate sb!bignum::%floor)
+  (:policy :fast-safe)
+  (:args (div-high :scs (unsigned-reg) :target rem)
+        (div-low :scs (unsigned-reg) :target quo)
+        (divisor :scs (unsigned-reg)))
+  (:arg-types unsigned-num unsigned-num unsigned-num)
+  (:results (quo :scs (unsigned-reg) :from (:argument 1))
+           (rem :scs (unsigned-reg) :from (:argument 0)))
+  (:result-types unsigned-num unsigned-num)
+  (:guard #!+(not (or :sparc-v8 :sparc-v9)) t
+         #!-(not (or :sparc-v8 :sparc-v9)) nil)
+  (:generator 300
+    (move rem div-high)
+    (move quo div-low)
+    (dotimes (i 33)
+      (let ((label (gen-label)))
+       (inst cmp rem divisor)
+       (inst b :ltu label)
+       (inst addxcc quo quo)
+       (inst sub rem divisor)
+       (emit-label label)
+       (unless (= i 32)
+         (inst addx rem rem))))
+    (inst not quo)))
+
+(define-vop (bignum-floor-v8)
+  (:translate sb!bignum::%floor)
+  (:policy :fast-safe)
+  (:args (div-high :scs (unsigned-reg) :target rem)
+        (div-low :scs (unsigned-reg) :target quo)
+        (divisor :scs (unsigned-reg)))
+  (:arg-types unsigned-num unsigned-num unsigned-num)
+  (:results (quo :scs (unsigned-reg) :from (:argument 1))
+           (rem :scs (unsigned-reg) :from (:argument 0)))
+  (:result-types unsigned-num unsigned-num)
+  (:temporary (:scs (unsigned-reg) :target quo) q)
+  ;; This vop is for a v8 or v9, provided we're also not using
+  ;; sparc-64, for which there a special sparc-64 vop.
+  (:guard #!+(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) t
+         #!-(or :sparc-v8 (and :sparc-v9 (not :sparc-64))) nil)
+  (:generator 15
+    (inst wry div-high)
+    (inst nop)
+    (inst nop)
+    (inst nop)
+    ;; Compute the quotient [Y, div-low] / divisor
+    (inst udiv q div-low divisor)
+    ;; Compute the remainder.  The high part of the result is in the Y
+    ;; register.
+    (inst umul rem q divisor)
+    (inst sub rem div-low rem)
+    (unless (location= quo q)
+      (move quo q))))
+
+(define-vop (bignum-floor-v9)
+  (:translate sb!bignum::%floor)
+  (:policy :fast-safe)
+  (:args (div-high :scs (unsigned-reg))
+        (div-low :scs (unsigned-reg))
+        (divisor :scs (unsigned-reg) :to (:result 1)))
+  (:arg-types unsigned-num unsigned-num unsigned-num)
+  (:temporary (:sc unsigned-reg :from (:argument 0)) dividend)
+  (:results (quo :scs (unsigned-reg))
+           (rem :scs (unsigned-reg)))
+  (:result-types unsigned-num unsigned-num)
+  (:guard #!+:sparc-64 t #!-:sparc-64 nil)
+  (:generator 5
+    ;; Set dividend to be div-high and div-low       
+    (inst sllx dividend div-high 32)
+    (inst add dividend div-low)
+    ;; Compute quotient
+    (inst udivx quo dividend divisor)
+    ;; Compute the remainder
+    (inst mulx rem quo divisor)
+    (inst sub rem dividend rem)))
+
+(define-vop (signify-digit)
+  (:translate sb!bignum::%fixnum-digit-with-correct-sign)
+  (:policy :fast-safe)
+  (:args (digit :scs (unsigned-reg) :target res))
+  (:arg-types unsigned-num)
+  (:results (res :scs (any-reg signed-reg)))
+  (:result-types signed-num)
+  (:generator 1
+    (sc-case res
+      (any-reg
+       (inst sll res digit fixnum-tag-bits))
+      (signed-reg
+       (move res digit)))))
+
+
+(define-vop (digit-ashr)
+  (:translate sb!bignum::%ashr)
+  (:policy :fast-safe)
+  (:args (digit :scs (unsigned-reg))
+        (count :scs (unsigned-reg)))
+  (:arg-types unsigned-num positive-fixnum)
+  (:results (result :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:generator 1
+    (inst sra result digit count)))
+
+(define-vop (digit-lshr digit-ashr)
+  (:translate sb!bignum::%digit-logical-shift-right)
+  (:generator 1
+    (inst srl result digit count)))
+
+(define-vop (digit-ashl digit-ashr)
+  (:translate sb!bignum::%ashl)
+  (:generator 1
+    (inst sll result digit count)))
+
+\f
+;;;; Static functions.
+
+(define-static-fun two-arg-gcd (x y) :translate gcd)
+(define-static-fun two-arg-lcm (x y) :translate lcm)
+
+(define-static-fun two-arg-+ (x y) :translate +)
+(define-static-fun two-arg-- (x y) :translate -)
+(define-static-fun two-arg-* (x y) :translate *)
+(define-static-fun two-arg-/ (x y) :translate /)
+
+(define-static-fun two-arg-< (x y) :translate <)
+(define-static-fun two-arg-<= (x y) :translate <=)
+(define-static-fun two-arg-> (x y) :translate >)
+(define-static-fun two-arg->= (x y) :translate >=)
+(define-static-fun two-arg-= (x y) :translate =)
+(define-static-fun two-arg-/= (x y) :translate /=)
+
+(define-static-fun %negate (x) :translate %negate)
+
+(define-static-fun two-arg-and (x y) :translate logand)
+(define-static-fun two-arg-ior (x y) :translate logior)
+(define-static-fun two-arg-xor (x y) :translate logxor)
+
+\f
+;; Need these so constant folding works with the deftransform.
+
+(defun ash-right-signed (num shift)
+  (declare (type (signed-byte #.sb!vm:n-word-bits) num)
+          (type (integer 0 #.(1- sb!vm:n-word-bits)) shift))
+  (ash-right-signed num shift))
+
+(defun ash-right-unsigned (num shift)
+  (declare (type (unsigned-byte #.sb!vm:n-word-bits) num)
+          (type (integer 0 #.(1- sb!vm:n-word-bits)) shift))
+  (ash-right-unsigned num shift))
+
+;; If we can prove that we have a right shift, just do the right shift
+;; instead of calling the inline ASH which has to check for the
+;; direction of the shift at run-time.
+(in-package "SB!C")
+
+(deftransform ash ((num shift) (integer integer))
+  (let ((num-type (continuation-type num))
+       (shift-type (continuation-type shift)))
+    ;; Can only handle right shifts
+    (unless (csubtypep shift-type (specifier-type '(integer * 0)))
+      (give-up-ir1-transform))
+
+    ;; If we can prove the shift is so large that all bits are shifted
+    ;; out, return the appropriate constant.  If the shift is small
+    ;; enough, call the VOP.  Otherwise, check for the shift size and
+    ;; do the appropriate thing.  (Hmm, could we just leave the IF
+    ;; s-expr and depend on other parts of the compiler to delete the
+    ;; unreachable parts, if any?)
+    (cond ((csubtypep num-type (specifier-type '(signed-byte #.sb!vm:n-word-bits)))
+          ;; A right shift by 31 is the same as a right shift by
+          ;; larger amount.  We get just the sign.
+          (if (csubtypep shift-type (specifier-type '(integer #.(- 1 sb!vm:n-word-bits) 0)))
+              ;; FIXME: ash-right-{un,}signed package problems
+              `(sb!vm::ash-right-signed num (- shift))
+              `(sb!vm::ash-right-signed num (min (- shift) #.(1- sb!vm:n-word-bits)))))
+         ((csubtypep num-type (specifier-type '(unsigned-byte #.sb!vm:n-word-bits)))
+          (if (csubtypep shift-type (specifier-type '(integer #.(- 1 sb!vm:n-word-bits) 0)))
+              `(sb!vm::ash-right-unsigned num (- shift))
+              `(if (<= shift #.(- sb!vm:n-word-bits))
+                0
+                (sb!vm::ash-right-unsigned num (- shift)))))
+         (t
+          (give-up-ir1-transform)))))
+
diff --git a/src/compiler/sparc/array.lisp b/src/compiler/sparc/array.lisp
new file mode 100644 (file)
index 0000000..8bbceaa
--- /dev/null
@@ -0,0 +1,716 @@
+;;;; the Sparc definitions for array operations
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; allocator for the array header.
+
+(define-vop (make-array-header)
+  (:translate make-array-header)
+  (:policy :fast-safe)
+  (:args (type :scs (any-reg))
+        (rank :scs (any-reg)))
+  (:arg-types tagged-num tagged-num)
+  (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) header)
+  (:temporary (:scs (non-descriptor-reg)) ndescr)
+  (:results (result :scs (descriptor-reg)))
+  (:generator 0
+    (pseudo-atomic ()
+      (inst or header alloc-tn other-pointer-lowtag)
+      (inst add ndescr rank (* (1+ array-dimensions-offset) n-word-bytes))
+      (inst andn ndescr 4)
+      (inst add alloc-tn ndescr)
+      (inst add ndescr rank (fixnumize (1- array-dimensions-offset)))
+      (inst sll ndescr ndescr n-widetag-bits)
+      (inst or ndescr ndescr type)
+      ;; Remove the extraneous fixnum tag bits because TYPE and RANK
+      ;; were fixnums
+      (inst srl ndescr ndescr fixnum-tag-bits)
+      (storew ndescr header 0 other-pointer-lowtag))
+    (move result header)))
+
+\f
+;;;; Additional accessors and setters for the array header.
+
+(defknown sb!impl::%array-dimension (t fixnum) fixnum
+  (flushable))
+(defknown sb!impl::%set-array-dimension (t fixnum fixnum) fixnum
+  ())
+
+(define-vop (%array-dimension word-index-ref)
+  (:translate sb!impl::%array-dimension)
+  (:policy :fast-safe)
+  (:variant array-dimensions-offset other-pointer-lowtag))
+
+(define-vop (%set-array-dimension word-index-set)
+  (:translate sb!impl::%set-array-dimension)
+  (:policy :fast-safe)
+  (:variant array-dimensions-offset other-pointer-lowtag))
+
+
+
+(defknown sb!impl::%array-rank (t) fixnum (flushable))
+
+(define-vop (array-rank-vop)
+  (:translate sb!impl::%array-rank)
+  (:policy :fast-safe)
+  (:args (x :scs (descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:results (res :scs (any-reg descriptor-reg)))
+  (:generator 6
+    (loadw temp x 0 other-pointer-lowtag)
+    (inst sra temp n-widetag-bits)
+    (inst sub temp (1- array-dimensions-offset))
+    (inst sll res temp fixnum-tag-bits)))
+
+
+\f
+;;;; Bounds checking routine.
+
+
+(define-vop (check-bound)
+  (:translate %check-bound)
+  (:policy :fast-safe)
+  (:args (array :scs (descriptor-reg))
+        (bound :scs (any-reg descriptor-reg))
+        (index :scs (any-reg descriptor-reg) :target result))
+  (:results (result :scs (any-reg descriptor-reg)))
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:generator 5
+    (let ((error (generate-error-code vop invalid-array-index-error
+                                     array bound index)))
+      (inst cmp index bound)
+      (inst b :geu error)
+      (inst nop)
+      (move result index))))
+
+
+\f
+;;;; Accessors/Setters
+
+;;; Variants built on top of word-index-ref, etc.  I.e. those vectors whos
+;;; elements are represented in integer registers and are built out of
+;;; 8, 16, or 32 bit elements.
+
+(macrolet ((def-data-vector-frobs (type variant element-type &rest scs)
+  `(progn
+     (define-vop (,(intern (concatenate 'simple-string
+                                       "DATA-VECTOR-REF/"
+                                       (string type)))
+                 ,(intern (concatenate 'simple-string
+                                       (string variant)
+                                       "-REF")))
+       (:note "inline array access")
+       (:variant vector-data-offset other-pointer-lowtag)
+       (:translate data-vector-ref)
+       (:arg-types ,type positive-fixnum)
+       (:results (value :scs ,scs))
+       (:result-types ,element-type))
+     (define-vop (,(intern (concatenate 'simple-string
+                                       "DATA-VECTOR-SET/"
+                                       (string type)))
+                 ,(intern (concatenate 'simple-string
+                                       (string variant)
+                                       "-SET")))
+       (:note "inline array store")
+       (:variant vector-data-offset other-pointer-lowtag)
+       (:translate data-vector-set)
+       (:arg-types ,type positive-fixnum ,element-type)
+       (:args (object :scs (descriptor-reg))
+             (index :scs (any-reg zero immediate))
+             (value :scs ,scs))
+       (:results (result :scs ,scs))
+       (:result-types ,element-type)))))
+
+  (def-data-vector-frobs simple-string byte-index
+    base-char base-char-reg)
+  (def-data-vector-frobs simple-vector word-index
+    * descriptor-reg any-reg)
+
+  (def-data-vector-frobs simple-array-unsigned-byte-8 byte-index
+    positive-fixnum unsigned-reg)
+  (def-data-vector-frobs simple-array-unsigned-byte-16 halfword-index
+    positive-fixnum unsigned-reg)
+  (def-data-vector-frobs simple-array-unsigned-byte-32 word-index
+    unsigned-num unsigned-reg)
+
+  (def-data-vector-frobs simple-array-signed-byte-30 word-index
+    tagged-num any-reg)
+  (def-data-vector-frobs simple-array-signed-byte-32 word-index
+    signed-num signed-reg)
+) ; MACROLET
+;;; Integer vectors whos elements are smaller than a byte.  I.e. bit, 2-bit,
+;;; and 4-bit vectors.
+;;; 
+
+(macrolet ((def-small-data-vector-frobs (type bits)
+  (let* ((elements-per-word (floor n-word-bits bits))
+        (bit-shift (1- (integer-length elements-per-word))))
+    `(progn
+       (define-vop (,(symbolicate 'data-vector-ref/ type))
+        (:note "inline array access")
+        (:translate data-vector-ref)
+        (:policy :fast-safe)
+        (:args (object :scs (descriptor-reg))
+               (index :scs (unsigned-reg)))
+        (:arg-types ,type positive-fixnum)
+        (:results (value :scs (any-reg)))
+        (:result-types positive-fixnum)
+        (:temporary (:scs (non-descriptor-reg) :to (:result 0)) temp result)
+        (:generator 20
+          (inst srl temp index ,bit-shift)
+          (inst sll temp fixnum-tag-bits)
+          (inst add temp (- (* vector-data-offset n-word-bytes)
+                            other-pointer-lowtag))
+          (inst ld result object temp)
+          (inst and temp index ,(1- elements-per-word))
+          (inst xor temp ,(1- elements-per-word))
+          ,@(unless (= bits 1)
+              `((inst sll temp ,(1- (integer-length bits)))))
+          (inst srl result temp)
+          (inst and result ,(1- (ash 1 bits)))
+          (inst sll value result 2)))
+       (define-vop (,(symbolicate 'data-vector-ref-c/ type))
+        (:translate data-vector-ref)
+        (:policy :fast-safe)
+        (:args (object :scs (descriptor-reg)))
+        (:arg-types ,type (:constant index))
+        (:info index)
+        (:results (result :scs (unsigned-reg)))
+        (:result-types positive-fixnum)
+        (:temporary (:scs (non-descriptor-reg)) temp)
+        (:generator 15
+          (multiple-value-bind (word extra) (floor index ,elements-per-word)
+            (setf extra (logxor extra (1- ,elements-per-word)))
+            (let ((offset (- (* (+ word vector-data-offset) n-word-bytes)
+                             other-pointer-lowtag)))
+              (cond ((typep offset '(signed-byte 13))
+                     (inst ld result object offset))
+                    (t
+                     (inst li temp offset)
+                     (inst ld result object temp))))
+            (unless (zerop extra)
+              (inst srl result
+                    (logxor (* extra ,bits) ,(1- elements-per-word))))
+            (unless (= extra ,(1- elements-per-word))
+              (inst and result ,(1- (ash 1 bits)))))))
+       (define-vop (,(symbolicate 'data-vector-set/ type))
+        (:note "inline array store")
+        (:translate data-vector-set)
+        (:policy :fast-safe)
+        (:args (object :scs (descriptor-reg))
+               (index :scs (unsigned-reg) :target shift)
+               (value :scs (unsigned-reg zero immediate) :target result))
+        (:arg-types ,type positive-fixnum positive-fixnum)
+        (:results (result :scs (unsigned-reg)))
+        (:result-types positive-fixnum)
+        (:temporary (:scs (non-descriptor-reg)) temp old offset)
+        (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) shift)
+        (:generator 25
+          (inst srl offset index ,bit-shift)
+          (inst sll offset fixnum-tag-bits)
+          (inst add offset (- (* vector-data-offset n-word-bytes)
+                              other-pointer-lowtag))
+          (inst ld old object offset)
+          (inst and shift index ,(1- elements-per-word))
+          (inst xor shift ,(1- elements-per-word))
+          ,@(unless (= bits 1)
+              `((inst sll shift ,(1- (integer-length bits)))))
+          (unless (and (sc-is value immediate)
+                       (= (tn-value value) ,(1- (ash 1 bits))))
+            (inst li temp ,(1- (ash 1 bits)))
+            (inst sll temp shift)
+            (inst not temp)
+            (inst and old temp))
+          (unless (sc-is value zero)
+            (sc-case value
+              (immediate
+               (inst li temp (logand (tn-value value) ,(1- (ash 1 bits)))))
+              (unsigned-reg
+               (inst and temp value ,(1- (ash 1 bits)))))
+            (inst sll temp shift)
+            (inst or old temp))
+          (inst st old object offset)
+          (sc-case value
+            (immediate
+             (inst li result (tn-value value)))
+            (t
+             (move result value)))))
+       (define-vop (,(symbolicate 'data-vector-set-c/ type))
+        (:translate data-vector-set)
+        (:policy :fast-safe)
+        (:args (object :scs (descriptor-reg))
+               (value :scs (unsigned-reg zero immediate) :target result))
+        (:arg-types ,type
+                    (:constant index)
+                    positive-fixnum)
+        (:info index)
+        (:results (result :scs (unsigned-reg)))
+        (:result-types positive-fixnum)
+        (:temporary (:scs (non-descriptor-reg)) offset-reg temp old)
+        (:generator 20
+          (multiple-value-bind (word extra) (floor index ,elements-per-word)
+            (let ((offset (- (* (+ word vector-data-offset) n-word-bytes)
+                             other-pointer-lowtag)))
+              (cond ((typep offset '(signed-byte 13))
+                     (inst ld old object offset))
+                    (t
+                     (inst li offset-reg offset)
+                     (inst ld old object offset-reg)))
+              (unless (and (sc-is value immediate)
+                           (= (tn-value value) ,(1- (ash 1 bits))))
+                (cond ((zerop extra)
+                       (inst sll old ,bits)
+                       (inst srl old ,bits))
+                      (t
+                       (inst li temp
+                             (lognot (ash ,(1- (ash 1 bits))
+                                          (* (logxor extra
+                                                     ,(1- elements-per-word))
+                                             ,bits))))
+                       (inst and old temp))))
+              (sc-case value
+                (zero)
+                (immediate
+                 (let ((value (ash (logand (tn-value value)
+                                           ,(1- (ash 1 bits)))
+                                   (* (logxor extra
+                                              ,(1- elements-per-word))
+                                      ,bits))))
+                   (cond ((typep value '(signed-byte 13))
+                          (inst or old value))
+                         (t
+                          (inst li temp value)
+                          (inst or old temp)))))
+                (unsigned-reg
+                 (inst sll temp value
+                       (* (logxor extra ,(1- elements-per-word)) ,bits))
+                 (inst or old temp)))
+              (if (typep offset '(signed-byte 13))
+                  (inst st old object offset)
+                  (inst st old object offset-reg)))
+            (sc-case value
+              (immediate
+               (inst li result (tn-value value)))
+              (t
+               (move result value))))))))))
+
+  (def-small-data-vector-frobs simple-bit-vector 1)
+  (def-small-data-vector-frobs simple-array-unsigned-byte-2 2)
+  (def-small-data-vector-frobs simple-array-unsigned-byte-4 4)
+
+) ; MACROLET
+
+
+;;; And the float variants.
+;;; 
+
+(define-vop (data-vector-ref/simple-array-single-float)
+  (:note "inline array access")
+  (:translate data-vector-ref)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg))
+        (index :scs (any-reg)))
+  (:arg-types simple-array-single-float positive-fixnum)
+  (:results (value :scs (single-reg)))
+  (:temporary (:scs (non-descriptor-reg)) offset)
+  (:result-types single-float)
+  (:generator 5
+    (inst add offset index (- (* vector-data-offset n-word-bytes)
+                             other-pointer-lowtag))
+    (inst ldf value object offset)))
+
+
+(define-vop (data-vector-set/simple-array-single-float)
+  (:note "inline array store")
+  (:translate data-vector-set)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg))
+        (index :scs (any-reg))
+        (value :scs (single-reg) :target result))
+  (:arg-types simple-array-single-float positive-fixnum single-float)
+  (:results (result :scs (single-reg)))
+  (:result-types single-float)
+  (:temporary (:scs (non-descriptor-reg)) offset)
+  (:generator 5
+    (inst add offset index
+         (- (* vector-data-offset n-word-bytes)
+            other-pointer-lowtag))
+    (inst stf value object offset)
+    (unless (location= result value)
+      (inst fmovs result value))))
+
+(define-vop (data-vector-ref/simple-array-double-float)
+  (:note "inline array access")
+  (:translate data-vector-ref)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg))
+        (index :scs (any-reg)))
+  (:arg-types simple-array-double-float positive-fixnum)
+  (:results (value :scs (double-reg)))
+  (:result-types double-float)
+  (:temporary (:scs (non-descriptor-reg)) offset)
+  (:generator 7
+    (inst sll offset index 1)
+    (inst add offset (- (* vector-data-offset n-word-bytes)
+                       other-pointer-lowtag))
+    (inst lddf value object offset)))
+
+(define-vop (data-vector-set/simple-array-double-float)
+  (:note "inline array store")
+  (:translate data-vector-set)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg))
+        (index :scs (any-reg))
+        (value :scs (double-reg) :target result))
+  (:arg-types simple-array-double-float positive-fixnum double-float)
+  (:results (result :scs (double-reg)))
+  (:result-types double-float)
+  (:temporary (:scs (non-descriptor-reg)) offset)
+  (:generator 20
+    (inst sll offset index 1)
+    (inst add offset (- (* vector-data-offset n-word-bytes)
+                       other-pointer-lowtag))
+    (inst stdf value object offset)
+    (unless (location= result value)
+      (move-double-reg result value))))
+
+#!+long-float
+(define-vop (data-vector-ref/simple-array-long-float)
+  (:note "inline array access")
+  (:translate data-vector-ref)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg))
+        (index :scs (any-reg)))
+  (:arg-types simple-array-long-float positive-fixnum)
+  (:results (value :scs (long-reg)))
+  (:result-types long-float)
+  (:temporary (:scs (non-descriptor-reg)) offset)
+  (:generator 7
+    (inst sll offset index 2)
+    (inst add offset (- (* vector-data-offset n-word-bytes)
+                       other-pointer-lowtag))
+    (load-long-reg value object offset nil)))
+
+#!+long-float
+(define-vop (data-vector-set/simple-array-long-float)
+  (:note "inline array store")
+  (:translate data-vector-set)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg))
+        (index :scs (any-reg))
+        (value :scs (long-reg) :target result))
+  (:arg-types simple-array-long-float positive-fixnum long-float)
+  (:results (result :scs (long-reg)))
+  (:result-types long-float)
+  (:temporary (:scs (non-descriptor-reg)) offset)
+  (:generator 20
+    (inst sll offset index 2)
+    (inst add offset (- (* vector-data-offset n-word-bytes)
+                       other-pointer-lowtag))
+    (store-long-reg value object offset nil)
+    (unless (location= result value)
+      (move-long-reg result value))))
+
+\f
+;;;; Misc. Array VOPs.
+
+
+#+nil
+(define-vop (vector-word-length)
+  (:args (vec :scs (descriptor-reg)))
+  (:results (res :scs (any-reg descriptor-reg)))
+  (:generator 6
+    (loadw res vec clc::g-vector-header-words)
+    (inst niuo res res clc::g-vector-words-mask-16)))
+
+(define-vop (get-vector-subtype get-header-data))
+(define-vop (set-vector-subtype set-header-data))
+
+\f
+;;;
+(define-vop (data-vector-ref/simple-array-signed-byte-8 signed-byte-index-ref)
+  (:note "inline array access")
+  (:variant vector-data-offset other-pointer-lowtag)
+  (:translate data-vector-ref)
+  (:arg-types simple-array-signed-byte-8 positive-fixnum)
+  (:results (value :scs (signed-reg)))
+  (:result-types tagged-num))
+
+(define-vop (data-vector-set/simple-array-signed-byte-8 byte-index-set)
+  (:note "inline array store")
+  (:variant vector-data-offset other-pointer-lowtag)
+  (:translate data-vector-set)
+  (:arg-types simple-array-signed-byte-8 positive-fixnum tagged-num)
+  (:args (object :scs (descriptor-reg))
+        (index :scs (any-reg zero immediate))
+        (value :scs (signed-reg)))
+  (:results (result :scs (signed-reg)))
+  (:result-types tagged-num))
+
+
+(define-vop (data-vector-ref/simple-array-signed-byte-16
+            signed-halfword-index-ref)
+  (:note "inline array access")
+  (:variant vector-data-offset other-pointer-lowtag)
+  (:translate data-vector-ref)
+  (:arg-types simple-array-signed-byte-16 positive-fixnum)
+  (:results (value :scs (signed-reg)))
+  (:result-types tagged-num))
+
+(define-vop (data-vector-set/simple-array-signed-byte-16 halfword-index-set)
+  (:note "inline array store")
+  (:variant vector-data-offset other-pointer-lowtag)
+  (:translate data-vector-set)
+  (:arg-types simple-array-signed-byte-16 positive-fixnum tagged-num)
+  (:args (object :scs (descriptor-reg))
+        (index :scs (any-reg zero immediate))
+        (value :scs (signed-reg)))
+  (:results (result :scs (signed-reg)))
+  (:result-types tagged-num))
+
+\f
+;;; Complex float arrays.
+
+(define-vop (data-vector-ref/simple-array-complex-single-float)
+  (:note "inline array access")
+  (:translate data-vector-ref)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg) :to :result)
+        (index :scs (any-reg)))
+  (:arg-types simple-array-complex-single-float positive-fixnum)
+  (:results (value :scs (complex-single-reg)))
+  (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset)
+  (:result-types complex-single-float)
+  (:generator 5
+    (let ((real-tn (complex-single-reg-real-tn value)))
+      (inst sll offset index 1)
+      (inst add offset (- (* vector-data-offset n-word-bytes)
+                         other-pointer-lowtag))
+      (inst ldf real-tn object offset))
+    (let ((imag-tn (complex-single-reg-imag-tn value)))
+      (inst add offset n-word-bytes)
+      (inst ldf imag-tn object offset))))
+
+(define-vop (data-vector-set/simple-array-complex-single-float)
+  (:note "inline array store")
+  (:translate data-vector-set)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg) :to :result)
+        (index :scs (any-reg))
+        (value :scs (complex-single-reg) :target result))
+  (:arg-types simple-array-complex-single-float positive-fixnum
+             complex-single-float)
+  (:results (result :scs (complex-single-reg)))
+  (:result-types complex-single-float)
+  (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset)
+  (:generator 5
+    (let ((value-real (complex-single-reg-real-tn value))
+         (result-real (complex-single-reg-real-tn result)))
+      (inst sll offset index 1)
+      (inst add offset (- (* vector-data-offset n-word-bytes)
+                         other-pointer-lowtag))
+      (inst stf value-real object offset)
+      (unless (location= result-real value-real)
+       (inst fmovs result-real value-real)))
+    (let ((value-imag (complex-single-reg-imag-tn value))
+         (result-imag (complex-single-reg-imag-tn result)))
+      (inst add offset n-word-bytes)
+      (inst stf value-imag object offset)
+      (unless (location= result-imag value-imag)
+       (inst fmovs result-imag value-imag)))))
+
+(define-vop (data-vector-ref/simple-array-complex-double-float)
+  (:note "inline array access")
+  (:translate data-vector-ref)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg) :to :result)
+        (index :scs (any-reg)))
+  (:arg-types simple-array-complex-double-float positive-fixnum)
+  (:results (value :scs (complex-double-reg)))
+  (:result-types complex-double-float)
+  (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset)
+  (:generator 7
+    (let ((real-tn (complex-double-reg-real-tn value)))
+      (inst sll offset index 2)
+      (inst add offset (- (* vector-data-offset n-word-bytes)
+                         other-pointer-lowtag))
+      (inst lddf real-tn object offset))
+    (let ((imag-tn (complex-double-reg-imag-tn value)))
+      (inst add offset (* 2 n-word-bytes))
+      (inst lddf imag-tn object offset))))
+
+(define-vop (data-vector-set/simple-array-complex-double-float)
+  (:note "inline array store")
+  (:translate data-vector-set)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg) :to :result)
+        (index :scs (any-reg))
+        (value :scs (complex-double-reg) :target result))
+  (:arg-types simple-array-complex-double-float positive-fixnum
+             complex-double-float)
+  (:results (result :scs (complex-double-reg)))
+  (:result-types complex-double-float)
+  (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset)
+  (:generator 20
+    (let ((value-real (complex-double-reg-real-tn value))
+         (result-real (complex-double-reg-real-tn result)))
+      (inst sll offset index 2)
+      (inst add offset (- (* vector-data-offset n-word-bytes)
+                         other-pointer-lowtag))
+      (inst stdf value-real object offset)
+      (unless (location= result-real value-real)
+       (move-double-reg result-real value-real)))
+    (let ((value-imag (complex-double-reg-imag-tn value))
+         (result-imag (complex-double-reg-imag-tn result)))
+      (inst add offset (* 2 n-word-bytes))
+      (inst stdf value-imag object offset)
+      (unless (location= result-imag value-imag)
+       (move-double-reg result-imag value-imag)))))
+
+#!+long-float
+(define-vop (data-vector-ref/simple-array-complex-long-float)
+  (:note "inline array access")
+  (:translate data-vector-ref)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg) :to :result)
+        (index :scs (any-reg)))
+  (:arg-types simple-array-complex-long-float positive-fixnum)
+  (:results (value :scs (complex-long-reg)))
+  (:result-types complex-long-float)
+  (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset)
+  (:generator 7
+    (let ((real-tn (complex-long-reg-real-tn value)))
+      (inst sll offset index 3)
+      (inst add offset (- (* vector-data-offset n-word-bytes)
+                         other-pointer-lowtag))
+      (load-long-reg real-tn object offset nil))
+    (let ((imag-tn (complex-long-reg-imag-tn value)))
+      (inst add offset (* 4 n-word-bytes))
+      (load-long-reg imag-tn object offset nil))))
+
+#!+long-float
+(define-vop (data-vector-set/simple-array-complex-long-float)
+  (:note "inline array store")
+  (:translate data-vector-set)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg) :to :result)
+        (index :scs (any-reg))
+        (value :scs (complex-long-reg) :target result))
+  (:arg-types simple-array-complex-long-float positive-fixnum
+             complex-long-float)
+  (:results (result :scs (complex-long-reg)))
+  (:result-types complex-long-float)
+  (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset)
+  (:generator 20
+    (let ((value-real (complex-long-reg-real-tn value))
+         (result-real (complex-long-reg-real-tn result)))
+      (inst sll offset index 3)
+      (inst add offset (- (* vector-data-offset n-word-bytes)
+                         other-pointer-lowtag))
+      (store-long-reg value-real object offset nil)
+      (unless (location= result-real value-real)
+       (move-long-reg result-real value-real)))
+    (let ((value-imag (complex-long-reg-imag-tn value))
+         (result-imag (complex-long-reg-imag-tn result)))
+      (inst add offset (* 4 n-word-bytes))
+      (store-long-reg value-imag object offset nil)
+      (unless (location= result-imag value-imag)
+       (move-long-reg result-imag value-imag)))))
+
+\f
+;;; These VOPs are used for implementing float slots in structures (whose raw
+;;; data is an unsigned-32 vector.
+;;;
+(define-vop (raw-ref-single data-vector-ref/simple-array-single-float)
+  (:translate %raw-ref-single)
+  (:arg-types simple-array-unsigned-byte-32 positive-fixnum))
+;;;
+(define-vop (raw-set-single data-vector-set/simple-array-single-float)
+  (:translate %raw-set-single)
+  (:arg-types simple-array-unsigned-byte-32 positive-fixnum single-float))
+;;;
+(define-vop (raw-ref-double data-vector-ref/simple-array-double-float)
+  (:translate %raw-ref-double)
+  (:arg-types simple-array-unsigned-byte-32 positive-fixnum))
+;;;
+(define-vop (raw-set-double data-vector-set/simple-array-double-float)
+  (:translate %raw-set-double)
+  (:arg-types simple-array-unsigned-byte-32 positive-fixnum double-float))
+;;;
+#!+long-float
+(define-vop (raw-ref-long data-vector-ref/simple-array-long-float)
+  (:translate %raw-ref-long)
+  (:arg-types simple-array-unsigned-byte-32 positive-fixnum))
+;;;
+#!+long-float
+(define-vop (raw-set-double data-vector-set/simple-array-long-float)
+  (:translate %raw-set-long)
+  (:arg-types simple-array-unsigned-byte-32 positive-fixnum long-float))
+
+(define-vop (raw-ref-complex-single
+            data-vector-ref/simple-array-complex-single-float)
+  (:translate %raw-ref-complex-single)
+  (:arg-types simple-array-unsigned-byte-32 positive-fixnum))
+;;;
+(define-vop (raw-set-complex-single
+            data-vector-set/simple-array-complex-single-float)
+  (:translate %raw-set-complex-single)
+  (:arg-types simple-array-unsigned-byte-32 positive-fixnum
+             complex-single-float))
+;;;
+(define-vop (raw-ref-complex-double
+            data-vector-ref/simple-array-complex-double-float)
+  (:translate %raw-ref-complex-double)
+  (:arg-types simple-array-unsigned-byte-32 positive-fixnum))
+;;;
+(define-vop (raw-set-complex-double
+            data-vector-set/simple-array-complex-double-float)
+  (:translate %raw-set-complex-double)
+  (:arg-types simple-array-unsigned-byte-32 positive-fixnum
+             complex-double-float))
+;;;
+#!+long-float
+(define-vop (raw-ref-complex-long
+            data-vector-ref/simple-array-complex-long-float)
+  (:translate %raw-ref-complex-long)
+  (:arg-types simple-array-unsigned-byte-32 positive-fixnum))
+;;;
+#!+long-float
+(define-vop (raw-set-complex-long
+            data-vector-set/simple-array-complex-long-float)
+  (:translate %raw-set-complex-long)
+  (:arg-types simple-array-unsigned-byte-32 positive-fixnum
+             complex-long-float))
+
+
+;;; These vops are useful for accessing the bits of a vector irrespective of
+;;; what type of vector it is.
+;;; 
+
+(define-vop (raw-bits word-index-ref)
+  (:note "raw-bits VOP")
+  (:translate %raw-bits)
+  (:results (value :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:variant 0 other-pointer-lowtag))
+
+(define-vop (set-raw-bits word-index-set)
+  (:note "setf raw-bits VOP")
+  (:translate %set-raw-bits)
+  (:args (object :scs (descriptor-reg))
+        (index :scs (any-reg zero immediate))
+        (value :scs (unsigned-reg)))
+  (:arg-types * tagged-num unsigned-num)
+  (:results (result :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:variant 0 other-pointer-lowtag))
diff --git a/src/compiler/sparc/backend-parms.lisp b/src/compiler/sparc/backend-parms.lisp
new file mode 100644 (file)
index 0000000..bdec468
--- /dev/null
@@ -0,0 +1,27 @@
+;;;; that part of the parms.lisp file from original CMU CL which is
+;;;; defined in terms of the BACKEND structure
+;;;;
+;;;; FIXME: Now that the BACKEND structure has been broken up, this
+;;;; might be mergeable back into the parms.lisp file.
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; compiler constants
+
+(defconstant +backend-fasl-file-implementation+ :sparc)
+
+(setf *backend-register-save-penalty* 3)
+
+(setf *backend-byte-order* :big-endian)
+
+(setf *backend-page-size* 8192)
+
diff --git a/src/compiler/sparc/c-call.lisp b/src/compiler/sparc/c-call.lisp
new file mode 100644 (file)
index 0000000..ba1fdda
--- /dev/null
@@ -0,0 +1,252 @@
+;;;; VOPs and other machine-specific support routines for call-out to C
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+(defun my-make-wired-tn (prim-type-name sc-name offset)
+  (make-wired-tn (primitive-type-or-lose prim-type-name)
+                (sc-number-or-lose sc-name)
+                offset))
+
+(defstruct arg-state
+  (register-args 0)
+  ;; No matter what we have to allocate at least 7 stack frame slots.  One
+  ;; because the C call convention requries it, and 6 because whoever we call
+  ;; is going to expect to be able to save his 6 register arguments there.
+  (stack-frame-size 7))
+
+(defun int-arg (state prim-type reg-sc stack-sc)
+  (let ((reg-args (arg-state-register-args state)))
+    (cond ((< reg-args 6)
+          (setf (arg-state-register-args state) (1+ reg-args))
+          (my-make-wired-tn prim-type reg-sc (+ reg-args nl0-offset)))
+         (t
+          (let ((frame-size (arg-state-stack-frame-size state)))
+            (setf (arg-state-stack-frame-size state) (1+ frame-size))
+            (my-make-wired-tn prim-type stack-sc (+ frame-size 16)))))))
+
+(define-alien-type-method (integer :arg-tn) (type state)
+  (if (alien-integer-type-signed type)
+      (int-arg state 'signed-byte-32 'signed-reg 'signed-stack)
+      (int-arg state 'unsigned-byte-32 'unsigned-reg 'unsigned-stack)))
+
+(define-alien-type-method (system-area-pointer :arg-tn) (type state)
+  (declare (ignore type))
+  (int-arg state 'system-area-pointer 'sap-reg 'sap-stack))
+
+(defstruct result-state
+  (num-results 0))
+
+(defun result-reg-offset (slot)
+  (ecase slot
+    (0 nl0-offset)
+    (1 nl1-offset)))
+
+(define-alien-type-method (integer :result-tn) (type state)
+  (let ((num-results (result-state-num-results state)))
+    (setf (result-state-num-results state) (1+ num-results))
+    (multiple-value-bind (ptype reg-sc)
+       (if (alien-integer-type-signed type)
+           (values 'signed-byte-32 'signed-reg)
+           (values 'unsigned-byte-32 'unsigned-reg))
+      (my-make-wired-tn ptype reg-sc (result-reg-offset num-results)))))
+  
+(define-alien-type-method (system-area-pointer :result-tn) (type state)
+  (declare (ignore type))
+  (let ((num-results (result-state-num-results state)))
+    (setf (result-state-num-results state) (1+ num-results))
+    (my-make-wired-tn 'system-area-pointer 'sap-reg
+                     (result-reg-offset num-results))))
+
+(define-alien-type-method (double-float :result-tn) (type state)
+  (declare (ignore type state))
+  (my-make-wired-tn 'double-float 'double-reg 0))
+
+(define-alien-type-method (single-float :result-tn) (type state)
+  (declare (ignore type state))
+  (my-make-wired-tn 'single-float 'single-reg 0))
+
+#!+long-float
+(define-alien-type-method (long-float :result-tn) (type)
+  (declare (ignore type))
+  (my-make-wired-tn 'long-float 'long-reg 0))
+
+(define-alien-type-method (values :result-tn) (type state)
+  (let ((values (alien-values-type-values type)))
+    (when (> (length values) 2)
+      (error "Too many result values from c-call."))
+    (mapcar #'(lambda (type)
+               (invoke-alien-type-method :result-tn type state))
+           values)))
+
+(!def-vm-support-routine make-call-out-tns (type)
+  (declare (type alien-fun-type type))
+  (let ((arg-state (make-arg-state)))
+    (collect ((arg-tns))
+      (dolist (arg-type (alien-fun-type-arg-types type))
+       (arg-tns (invoke-alien-type-method :arg-tn arg-type arg-state)))
+      (values (my-make-wired-tn 'positive-fixnum 'any-reg nsp-offset)
+             (* (arg-state-stack-frame-size arg-state) n-word-bytes)
+             (arg-tns)
+             (invoke-alien-type-method
+              :result-tn
+              (alien-fun-type-result-type type)
+              (make-result-state))))))
+
+(deftransform %alien-funcall ((function type &rest args))
+  (assert (sb!c::constant-continuation-p type))
+  (let* ((type (sb!c::continuation-value type))
+        (arg-types (alien-fun-type-arg-types type))
+        (result-type (alien-fun-type-result-type type)))
+    (assert (= (length arg-types) (length args)))
+    ;; We need to do something special for the following argument
+    ;; types: single-float, double-float, and 64-bit integers.  For
+    ;; results, we need something special for 64-bit integer results.
+    (if (or (some #'alien-single-float-type-p arg-types)
+           (some #'alien-double-float-type-p arg-types)
+           (some #'(lambda (type)
+                     (and (alien-integer-type-p type)
+                          (> (sb!alien::alien-integer-type-bits type) 32)))
+                 arg-types)
+           #!+long-float (some #'alien-long-float-type-p arg-types)
+           (and (alien-integer-type-p result-type)
+                (> (sb!alien::alien-integer-type-bits result-type) 32)))
+       (collect ((new-args) (lambda-vars) (new-arg-types))
+                (dolist (type arg-types)
+                  (let ((arg (gensym)))
+                    (lambda-vars arg)
+                    (cond ((and (alien-integer-type-p type)
+                                (> (sb!alien::alien-integer-type-bits type) 32))
+                           ;; 64-bit long long types are stored in
+                           ;; consecutive locations, most significant word
+                           ;; first (big-endian).
+                           (new-args `(ash ,arg -32))
+                           (new-args `(logand ,arg #xffffffff))
+                           (if (alien-integer-type-signed type)
+                               (new-arg-types (parse-alien-type '(signed 32) (sb!kernel:make-null-lexenv)))
+                               (new-arg-types (parse-alien-type '(unsigned 32) (sb!kernel:make-null-lexenv))))
+                           (new-arg-types (parse-alien-type '(unsigned 32) (sb!kernel:make-null-lexenv))))
+                          ((alien-single-float-type-p type)
+                           (new-args `(single-float-bits ,arg))
+                           (new-arg-types (parse-alien-type '(signed 32) (sb!kernel:make-null-lexenv))))
+                          ((alien-double-float-type-p type)
+                           (new-args `(double-float-high-bits ,arg))
+                           (new-args `(double-float-low-bits ,arg))
+                           (new-arg-types (parse-alien-type '(signed 32) (sb!kernel:make-null-lexenv)))
+                           (new-arg-types (parse-alien-type '(unsigned 32) (sb!kernel:make-null-lexenv))))
+                          #!+long-float
+                          ((alien-long-float-type-p type)
+                           (new-args `(long-float-exp-bits ,arg))
+                           (new-args `(long-float-high-bits ,arg))
+                           (new-args `(long-float-mid-bits ,arg))
+                           (new-args `(long-float-low-bits ,arg))
+                           (new-arg-types (parse-alien-type '(signed 32) (sb!kernel:make-null-lexenv)))
+                           (new-arg-types (parse-alien-type '(unsigned 32) (sb!kernel:make-null-lexenv)))
+                           (new-arg-types (parse-alien-type '(unsigned 32) (sb!kernel:make-null-lexenv)))
+                           (new-arg-types (parse-alien-type '(unsigned 32) (sb!kernel:make-null-lexenv))))
+                          (t
+                           (new-args arg)
+                           (new-arg-types type)))))
+                (cond ((and (alien-integer-type-p result-type)
+                            (> (sb!alien::alien-integer-type-bits result-type) 32))
+                       (let ((new-result-type
+                              (let ((sb!alien::*values-type-okay* t))
+                                (parse-alien-type
+                                 (if (alien-integer-type-signed result-type)
+                                     '(values (signed 32) (unsigned 32))
+                                     '(values (unsigned 32) (unsigned 32)))
+                                 (sb!kernel:make-null-lexenv)))))
+                         `(lambda (function type ,@(lambda-vars))
+                           (declare (ignore type))
+                           (multiple-value-bind (high low)
+                               (%alien-funcall function
+                                               ',(make-alien-fun-type
+                                                  :arg-types (new-arg-types)
+                                                  :result-type new-result-type)
+                                               ,@(new-args))
+                             (logior low (ash high 32))))))
+                      (t
+                       `(lambda (function type ,@(lambda-vars))
+                         (declare (ignore type))
+                         (%alien-funcall function
+                          ',(make-alien-fun-type
+                             :arg-types (new-arg-types)
+                             :result-type result-type)
+                          ,@(new-args))))))
+       (sb!c::give-up-ir1-transform))))
+
+
+(define-vop (foreign-symbol-address)
+  (:translate foreign-symbol-address)
+  (:policy :fast-safe)
+  (:args)
+  (:arg-types (:constant simple-string))
+  (:info foreign-symbol)
+  (:results (res :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:generator 2
+    (inst li res (make-fixup (extern-alien-name foreign-symbol)
+                            :foreign))))
+
+(define-vop (call-out)
+  (:args (function :scs (sap-reg) :target cfunc)
+        (args :more t))
+  (:results (results :more t))
+  (:ignore args results)
+  (:save-p t)
+  (:temporary (:sc any-reg :offset cfunc-offset
+                  :from (:argument 0) :to (:result 0)) cfunc)
+  (:temporary (:sc interior-reg :offset lip-offset) lip)
+  (:temporary (:scs (any-reg) :to (:result 0)) temp)
+  (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)
+  (:vop-var vop)
+  (:generator 0
+    (let ((cur-nfp (current-nfp-tn vop)))
+      (when cur-nfp
+       (store-stack-tn nfp-save cur-nfp))
+      (move cfunc function)
+      (inst li temp (make-fixup (extern-alien-name "call_into_c") :foreign))
+      (inst jal lip temp)
+      (inst nop)
+      (when cur-nfp
+       (load-stack-tn cur-nfp nfp-save)))))
+
+
+(define-vop (alloc-number-stack-space)
+  (:info amount)
+  (:results (result :scs (sap-reg any-reg)))
+  (:temporary (:scs (unsigned-reg) :to (:result 0)) temp)
+  (:generator 0
+    (unless (zerop amount)
+      (let ((delta (logandc2 (+ amount 7) 7)))
+       (cond ((< delta (ash 1 12))
+              (inst sub nsp-tn delta))
+             (t
+              (inst li temp delta)
+              (inst sub nsp-tn temp)))))
+    (unless (location= result nsp-tn)
+      ;; They are only location= when the result tn was allocated by
+      ;; make-call-out-tns above, which takes the number-stack-displacement
+      ;; into account itself.
+      (inst add result nsp-tn number-stack-displacement))))
+
+(define-vop (dealloc-number-stack-space)
+  (:info amount)
+  (:policy :fast-safe)
+  (:temporary (:scs (unsigned-reg) :to (:result 0)) temp)
+  (:generator 0
+    (unless (zerop amount)
+      (let ((delta (logandc2 (+ amount 7) 7)))
+       (cond ((< delta (ash 1 12))
+              (inst add nsp-tn delta))
+             (t
+              (inst li temp delta)
+              (inst add nsp-tn temp)))))))
diff --git a/src/compiler/sparc/call.lisp b/src/compiler/sparc/call.lisp
new file mode 100644 (file)
index 0000000..8cde5f8
--- /dev/null
@@ -0,0 +1,1193 @@
+;;;; the VM definition of function call for the Sparc
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+\f
+;;;; Interfaces to IR2 conversion:
+
+;;; Return a wired TN describing the N'th full call argument passing
+;;; location.
+(!def-vm-support-routine standard-arg-location (n)
+  (declare (type unsigned-byte n))
+  (if (< n register-arg-count)
+      (make-wired-tn *backend-t-primitive-type* register-arg-scn
+                    (elt *register-arg-offsets* n))
+      (make-wired-tn *backend-t-primitive-type* control-stack-arg-scn n)))
+
+
+;;; Make a passing location TN for a local call return PC.  If
+;;; standard is true, then use the standard (full call) location,
+;;; otherwise use any legal location.  Even in the non-standard case,
+;;; this may be restricted by a desire to use a subroutine call
+;;; instruction.
+(!def-vm-support-routine make-return-pc-passing-location (standard)
+  (if standard
+      (make-wired-tn *backend-t-primitive-type* register-arg-scn lra-offset)
+      (make-restricted-tn *backend-t-primitive-type* register-arg-scn)))
+
+;;; Similar to Make-Return-PC-Passing-Location, but makes a location
+;;; to pass Old-FP in.  This is (obviously) wired in the standard
+;;; convention, but is totally unrestricted in non-standard
+;;; conventions, since we can always fetch it off of the stack using
+;;; the arg pointer.
+(!def-vm-support-routine make-old-fp-passing-location (standard)
+  (if standard
+      (make-wired-tn *fixnum-primitive-type* immediate-arg-scn ocfp-offset)
+      (make-normal-tn *fixnum-primitive-type*)))
+
+;;; Make the TNs used to hold Old-FP and Return-PC within the current
+;;; function.  We treat these specially so that the debugger can find
+;;; them at a known location.
+(!def-vm-support-routine make-old-fp-save-location (env)
+  (specify-save-tn
+   (physenv-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env)
+   (make-wired-tn *fixnum-primitive-type*
+                 control-stack-arg-scn
+                 ocfp-save-offset)))
+
+(!def-vm-support-routine make-return-pc-save-location (env)
+  (specify-save-tn
+   (physenv-debug-live-tn (make-normal-tn *backend-t-primitive-type*) env)
+   (make-wired-tn *backend-t-primitive-type*
+                 control-stack-arg-scn
+                 lra-save-offset)))
+
+;;; Make a TN for the standard argument count passing location.  We
+;;; only need to make the standard location, since a count is never
+;;; passed when we are using non-standard conventions.
+(!def-vm-support-routine make-arg-count-location ()
+  (make-wired-tn *fixnum-primitive-type* immediate-arg-scn nargs-offset))
+
+
+;;; Make a TN to hold the number-stack frame pointer.  This is
+;;; allocated once per component, and is component-live.
+(!def-vm-support-routine make-nfp-tn ()
+  (component-live-tn
+   (make-wired-tn *fixnum-primitive-type* immediate-arg-scn nfp-offset)))
+
+(!def-vm-support-routine make-stack-pointer-tn ()
+  (make-normal-tn *fixnum-primitive-type*))
+
+(!def-vm-support-routine make-number-stack-pointer-tn ()
+  (make-normal-tn *fixnum-primitive-type*))
+
+;;; Return a list of TNs that can be used to represent an
+;;; unknown-values continuation within a function.
+(!def-vm-support-routine make-unknown-values-locations ()
+  (list (make-stack-pointer-tn)
+       (make-normal-tn *fixnum-primitive-type*)))
+
+
+;;; This function is called by the Entry-Analyze phase, allowing
+;;; VM-dependent initialization of the IR2-Component structure.  We push
+;;; placeholder entries in the Constants to leave room for additional
+;;; noise in the code object header.
+(!def-vm-support-routine select-component-format (component)
+  (declare (type component component))
+  (dotimes (i code-constants-offset)
+    (vector-push-extend nil
+                       (ir2-component-constants (component-info component))))
+  (values))
+\f
+;;;; Frame hackery:
+
+;;; Return the number of bytes needed for the current non-descriptor
+;;; stack frame.  Non-descriptor stack frames must be multiples of 8
+;;; bytes on the PMAX.
+(defun bytes-needed-for-non-descriptor-stack-frame ()
+  (* (logandc2 (1+ (sb-allocated-size 'non-descriptor-stack)) 1)
+     n-word-bytes))
+
+;;; Used for setting up the Old-FP in local call.
+(define-vop (current-fp)
+  (:results (val :scs (any-reg)))
+  (:generator 1
+    (move val cfp-tn)))
+
+;;; Used for computing the caller's NFP for use in known-values return.  Only
+;;; works assuming there is no variable size stuff on the nstack.
+;;;
+(define-vop (compute-old-nfp)
+  (:results (val :scs (any-reg)))
+  (:vop-var vop)
+  (:generator 1
+    (let ((nfp (current-nfp-tn vop)))
+      (when nfp
+       (inst add val nfp (bytes-needed-for-non-descriptor-stack-frame))))))
+
+
+(define-vop (xep-allocate-frame)
+  (:info start-lab copy-more-arg-follows)
+  (:ignore copy-more-arg-follows)
+  (:vop-var vop)
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:generator 1
+    ;; Make sure the function is aligned, and drop a label pointing to this
+    ;; function header.
+    (align n-lowtag-bits)
+    (trace-table-entry trace-table-fun-prologue)
+    (emit-label start-lab)
+    ;; Allocate function header.
+    (inst simple-fun-header-word)
+    (dotimes (i (1- simple-fun-code-offset))
+      (inst word 0))
+    ;; The start of the actual code.
+    ;; Fix CODE, cause the function object was passed in.
+    (inst compute-code-from-fn code-tn code-tn start-lab temp)
+    ;; Build our stack frames.
+    (inst add csp-tn cfp-tn
+         (* n-word-bytes (sb-allocated-size 'control-stack)))
+    (let ((nfp-tn (current-nfp-tn vop)))
+      (when nfp-tn
+       (inst sub nsp-tn (bytes-needed-for-non-descriptor-stack-frame))
+       (inst add nfp-tn nsp-tn number-stack-displacement)))
+    (trace-table-entry trace-table-normal)))
+
+(define-vop (allocate-frame)
+  (:results (res :scs (any-reg))
+           (nfp :scs (any-reg)))
+  (:info callee)
+  (:generator 2
+    (trace-table-entry trace-table-fun-prologue)
+    (move res csp-tn)
+    (inst add csp-tn csp-tn
+         (* n-word-bytes (sb-allocated-size 'control-stack)))
+    (when (ir2-physenv-number-stack-p callee)
+      (inst sub nsp-tn (bytes-needed-for-non-descriptor-stack-frame))
+      (inst add nfp nsp-tn number-stack-displacement))
+    (trace-table-entry trace-table-normal)))
+
+;;; Allocate a partial frame for passing stack arguments in a full call.  Nargs
+;;; is the number of arguments passed.  If no stack arguments are passed, then
+;;; we don't have to do anything.
+;;;
+(define-vop (allocate-full-call-frame)
+  (:info nargs)
+  (:results (res :scs (any-reg)))
+  (:generator 2
+    (when (> nargs register-arg-count)
+      (move res csp-tn)
+      (inst add csp-tn csp-tn (* nargs n-word-bytes)))))
+
+
+
+\f
+;;; Emit code needed at the return-point from an unknown-values call
+;;; for a fixed number of values.  Values is the head of the TN-Ref
+;;; list for the locations that the values are to be received into.
+;;; Nvals is the number of values that are to be received (should
+;;; equal the length of Values).
+;;;
+;;; Move-Temp is a Descriptor-Reg TN used as a temporary.
+;;;
+;;; This code exploits the fact that in the unknown-values convention,
+;;; a single value return returns at the return PC + 8, whereas a
+;;; return of other than one value returns directly at the return PC.
+;;;
+;;; If 0 or 1 values are expected, then we just emit an instruction to
+;;; reset the SP (which will only be executed when other than 1 value
+;;; is returned.)
+;;;
+;;; In the general case, we have to do three things:
+;;;  -- Default unsupplied register values.  This need only be done when a
+;;;     single value is returned, since register values are defaulted by the
+;;;     called in the non-single case.
+;;;  -- Default unsupplied stack values.  This needs to be done whenever there
+;;;     are stack values.
+;;;  -- Reset SP.  This must be done whenever other than 1 value is returned,
+;;;     regardless of the number of values desired.
+;;;
+;;; The general-case code looks like this:
+#|
+       b regs-defaulted                ; Skip if MVs
+       nop
+
+       move a1 null-tn                 ; Default register values
+       ...
+       loadi nargs 1                   ; Force defaulting of stack values
+       move old-fp csp                 ; Set up args for SP resetting
+
+regs-defaulted
+       subcc temp nargs register-arg-count
+
+       b :lt default-value-7   ; jump to default code
+       loadw move-temp ocfp-tn 6       ; Move value to correct location.
+        subcc temp 1
+       store-stack-tn val4-tn move-temp
+
+       b :lt default-value-8
+       loadw move-temp ocfp-tn 7
+        subcc temp 1
+       store-stack-tn val5-tn move-temp
+
+       ...
+
+defaulting-done
+       move csp ocfp                   ; Reset SP.
+<end of code>
+
+<elsewhere>
+default-value-7
+       store-stack-tn val4-tn null-tn  ; Nil out 7'th value. (first on stack)
+
+default-value-8
+       store-stack-tn val5-tn null-tn  ; Nil out 8'th value.
+
+       ...
+
+       br defaulting-done
+        nop
+|#
+(defun default-unknown-values (vop values nvals move-temp temp lra-label)
+  (declare (type (or tn-ref null) values)
+          (type unsigned-byte nvals) (type tn move-temp temp))
+  (if (<= nvals 1)
+      (progn
+       (without-scheduling ()
+         (note-this-location vop :single-value-return)
+         (move csp-tn ocfp-tn)
+         (inst nop))
+       (inst compute-code-from-lra code-tn code-tn lra-label temp))
+      (let ((regs-defaulted (gen-label))
+           (defaulting-done (gen-label))
+           (default-stack-vals (gen-label)))
+       ;; Branch off to the MV case.
+       (without-scheduling ()
+         (note-this-location vop :unknown-return)
+         (inst b regs-defaulted)
+         (if (> nvals register-arg-count)
+             (inst subcc temp nargs-tn (fixnumize register-arg-count))
+             (move csp-tn ocfp-tn)))
+       
+       ;; Do the single value calse.
+       (do ((i 1 (1+ i))
+            (val (tn-ref-across values) (tn-ref-across val)))
+           ((= i (min nvals register-arg-count)))
+         (move (tn-ref-tn val) null-tn))
+       (when (> nvals register-arg-count)
+         (inst b default-stack-vals)
+         (move ocfp-tn csp-tn))
+       
+       (emit-label regs-defaulted)
+       (when (> nvals register-arg-count)
+         (collect ((defaults))
+           (do ((i register-arg-count (1+ i))
+                (val (do ((i 0 (1+ i))
+                          (val values (tn-ref-across val)))
+                         ((= i register-arg-count) val))
+                     (tn-ref-across val)))
+               ((null val))
+             
+             (let ((default-lab (gen-label))
+                   (tn (tn-ref-tn val)))
+               (defaults (cons default-lab tn))
+               
+               (inst b :le default-lab)
+               (inst ld move-temp ocfp-tn (* i n-word-bytes))
+               (inst subcc temp (fixnumize 1))
+               (store-stack-tn tn move-temp)))
+           
+           (emit-label defaulting-done)
+           (move csp-tn ocfp-tn)
+           
+           (let ((defaults (defaults)))
+             (when defaults
+               (assemble (*elsewhere*)
+                 (emit-label default-stack-vals)
+                 (trace-table-entry trace-table-fun-prologue)
+                 (do ((remaining defaults (cdr remaining)))
+                     ((null remaining))
+                   (let ((def (car remaining)))
+                     (emit-label (car def))
+                     (when (null (cdr remaining))
+                       (inst b defaulting-done))
+                     (store-stack-tn (cdr def) null-tn)))
+                 (trace-table-entry trace-table-normal))))))
+
+       (inst compute-code-from-lra code-tn code-tn lra-label temp)))
+  (values))
+
+\f
+;;; Receive-Unknown-Values  --  Internal
+;;;
+;;; Emit code needed at the return point for an unknown-values call
+;;; for an arbitrary number of values.
+;;;
+;;; We do the single and non-single cases with no shared code: there
+;;; doesn't seem to be any potential overlap, and receiving a single
+;;; value is more important efficiency-wise.
+;;;
+;;; When there is a single value, we just push it on the stack,
+;;; returning the old SP and 1.
+;;;
+;;; When there is a variable number of values, we move all of the
+;;; argument registers onto the stack, and return Args and Nargs.
+;;;
+;;; Args and Nargs are TNs wired to the named locations.  We must
+;;; explicitly allocate these TNs, since their lifetimes overlap with
+;;; the results Start and Count (also, it's nice to be able to target
+;;; them).
+(defun receive-unknown-values (args nargs start count lra-label temp)
+  (declare (type tn args nargs start count temp))
+  (let ((variable-values (gen-label))
+       (done (gen-label)))
+    (without-scheduling ()
+      (inst b variable-values)
+      (inst nop))
+    
+    (inst compute-code-from-lra code-tn code-tn lra-label temp)
+    (inst add csp-tn 4)
+    (storew (first *register-arg-tns*) csp-tn -1)
+    (inst sub start csp-tn 4)
+    (inst li count (fixnumize 1))
+    
+    (emit-label done)
+    
+    (assemble (*elsewhere*)
+      (trace-table-entry trace-table-fun-prologue)
+      (emit-label variable-values)
+      (inst compute-code-from-lra code-tn code-tn lra-label temp)
+      (do ((arg *register-arg-tns* (rest arg))
+          (i 0 (1+ i)))
+         ((null arg))
+       (storew (first arg) args i))
+      (move start args)
+      (move count nargs)
+      (inst b done)
+      (inst nop)
+      (trace-table-entry trace-table-normal)))
+  (values))
+
+
+;;; VOP that can be inherited by unknown values receivers.  The main
+;;; thing this handles is allocation of the result temporaries.
+(define-vop (unknown-values-receiver)
+  (:results
+   (start :scs (any-reg))
+   (count :scs (any-reg)))
+  (:temporary (:sc descriptor-reg :offset ocfp-offset
+                  :from :eval :to (:result 0))
+             values-start)
+  (:temporary (:sc any-reg :offset nargs-offset
+              :from :eval :to (:result 1))
+             nvals)
+  (:temporary (:scs (non-descriptor-reg)) temp))
+
+
+\f
+;;;; Local call with unknown values convention return:
+
+;;; Non-TR local call for a fixed number of values passed according to the
+;;; unknown values convention.
+;;;
+;;; Args are the argument passing locations, which are specified only to
+;;; terminate their lifetimes in the caller.
+;;;
+;;; Values are the return value locations (wired to the standard passing
+;;; locations).
+;;;
+;;; Save is the save info, which we can ignore since saving has been done.
+;;; Return-PC is the TN that the return PC should be passed in.
+;;; Target is a continuation pointing to the start of the called function.
+;;; Nvals is the number of values received.
+;;;
+;;; Note: we can't use normal load-tn allocation for the fixed args, since all
+;;; registers may be tied up by the more operand.  Instead, we use
+;;; MAYBE-LOAD-STACK-TN.
+(define-vop (call-local)
+  (:args (fp)
+        (nfp)
+        (args :more t))
+  (:results (values :more t))
+  (:save-p t)
+  (:move-args :local-call)
+  (:info arg-locs callee target nvals)
+  (:vop-var vop)
+  (:temporary (:scs (descriptor-reg) :from (:eval 0)) move-temp)
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)
+  (:temporary (:sc any-reg :offset ocfp-offset :from (:eval 0)) ocfp)
+  (:ignore arg-locs args ocfp)
+  (:generator 5
+    (trace-table-entry trace-table-call-site)
+    (let ((label (gen-label))
+         (cur-nfp (current-nfp-tn vop)))
+      (when cur-nfp
+       (store-stack-tn nfp-save cur-nfp))
+      (let ((callee-nfp (callee-nfp-tn callee)))
+       (when callee-nfp
+         (maybe-load-stack-tn callee-nfp nfp)))
+      (maybe-load-stack-tn cfp-tn fp)
+      (inst compute-lra-from-code
+           (callee-return-pc-tn callee) code-tn label temp)
+      (note-this-location vop :call-site)
+      (inst b target)
+      (inst nop)
+      (emit-return-pc label)
+      (default-unknown-values vop values nvals move-temp temp label)
+      (when cur-nfp
+       (load-stack-tn cur-nfp nfp-save)))
+    (trace-table-entry trace-table-normal)))
+
+
+;;; Non-TR local call for a variable number of return values passed according
+;;; to the unknown values convention.  The results are the start of the values
+;;; glob and the number of values received.
+;;;
+;;; Note: we can't use normal load-tn allocation for the fixed args, since all
+;;; registers may be tied up by the more operand.  Instead, we use
+;;; MAYBE-LOAD-STACK-TN.
+(define-vop (multiple-call-local unknown-values-receiver)
+  (:args (fp)
+        (nfp)
+        (args :more t))
+  (:save-p t)
+  (:move-args :local-call)
+  (:info save callee target)
+  (:ignore args save)
+  (:vop-var vop)
+  (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)
+  (:generator 20
+    (trace-table-entry trace-table-call-site)
+    (let ((label (gen-label))
+         (cur-nfp (current-nfp-tn vop)))
+      (when cur-nfp
+       (store-stack-tn nfp-save cur-nfp))
+      (let ((callee-nfp (callee-nfp-tn callee)))
+       (when callee-nfp
+         (maybe-load-stack-tn callee-nfp nfp)))
+      (maybe-load-stack-tn cfp-tn fp)
+      (inst compute-lra-from-code
+           (callee-return-pc-tn callee) code-tn label temp)
+      (note-this-location vop :call-site)
+      (inst b target)
+      (inst nop)
+      (emit-return-pc label)
+      (note-this-location vop :unknown-return)
+      (receive-unknown-values values-start nvals start count label temp)
+      (when cur-nfp
+       (load-stack-tn cur-nfp nfp-save)))
+    (trace-table-entry trace-table-normal)))
+
+\f
+;;;; Local call with known values return:
+
+;;; Non-TR local call with known return locations.  Known-value return works
+;;; just like argument passing in local call.
+;;;
+;;; Note: we can't use normal load-tn allocation for the fixed args, since all
+;;; registers may be tied up by the more operand.  Instead, we use
+;;; MAYBE-LOAD-STACK-TN.
+(define-vop (known-call-local)
+  (:args (fp)
+        (nfp)
+        (args :more t))
+  (:results (res :more t))
+  (:move-args :local-call)
+  (:save-p t)
+  (:info save callee target)
+  (:ignore args res save)
+  (:vop-var vop)
+  (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:generator 5
+    (trace-table-entry trace-table-call-site)
+    (let ((label (gen-label))
+         (cur-nfp (current-nfp-tn vop)))
+      (when cur-nfp
+       (store-stack-tn nfp-save cur-nfp))
+      (let ((callee-nfp (callee-nfp-tn callee)))
+       (when callee-nfp
+         (maybe-load-stack-tn callee-nfp nfp)))
+      (maybe-load-stack-tn cfp-tn fp)
+      (inst compute-lra-from-code
+           (callee-return-pc-tn callee) code-tn label temp)
+      (note-this-location vop :call-site)
+      (inst b target)
+      (inst nop)
+      (emit-return-pc label)
+      (note-this-location vop :known-return)
+      (when cur-nfp
+       (load-stack-tn cur-nfp nfp-save)))
+    (trace-table-entry trace-table-normal)))
+
+;;; Return from known values call.  We receive the return locations as
+;;; arguments to terminate their lifetimes in the returning function.  We
+;;; restore FP and CSP and jump to the Return-PC.
+;;;
+;;; Note: we can't use normal load-tn allocation for the fixed args, since all
+;;; registers may be tied up by the more operand.  Instead, we use
+;;; MAYBE-LOAD-STACK-TN.
+(define-vop (known-return)
+  (:args (old-fp :target old-fp-temp)
+        (return-pc :target return-pc-temp)
+        (vals :more t))
+  (:temporary (:sc any-reg :from (:argument 0)) old-fp-temp)
+  (:temporary (:sc descriptor-reg :from (:argument 1)) return-pc-temp)
+  (:move-args :known-return)
+  (:info val-locs)
+  (:ignore val-locs vals)
+  (:vop-var vop)
+  (:generator 6
+    (trace-table-entry trace-table-fun-epilogue)
+    (maybe-load-stack-tn old-fp-temp old-fp)
+    (maybe-load-stack-tn return-pc-temp return-pc)
+    (move csp-tn cfp-tn)
+    (let ((cur-nfp (current-nfp-tn vop)))
+      (when cur-nfp
+       (inst add nsp-tn cur-nfp 
+             (- (bytes-needed-for-non-descriptor-stack-frame)
+                number-stack-displacement))))
+    (inst j return-pc-temp (- n-word-bytes other-pointer-lowtag))
+    (move cfp-tn old-fp-temp)
+    (trace-table-entry trace-table-normal)))
+
+\f
+;;;; Full call:
+;;;
+;;; There is something of a cross-product effect with full calls.
+;;; Different versions are used depending on whether we know the
+;;; number of arguments or the name of the called function, and
+;;; whether we want fixed values, unknown values, or a tail call.
+;;;
+;;; In full call, the arguments are passed creating a partial frame on
+;;; the stack top and storing stack arguments into that frame.  On
+;;; entry to the callee, this partial frame is pointed to by FP.  If
+;;; there are no stack arguments, we don't bother allocating a partial
+;;; frame, and instead set FP to SP just before the call.
+
+;;; This macro helps in the definition of full call VOPs by avoiding code
+;;; replication in defining the cross-product VOPs.
+;;;
+;;; Name is the name of the VOP to define.
+;;; 
+;;; Named is true if the first argument is a symbol whose global function
+;;; definition is to be called.
+;;;
+;;; Return is either :Fixed, :Unknown or :Tail:
+;;; -- If :Fixed, then the call is for a fixed number of values, returned in
+;;;    the standard passing locations (passed as result operands).
+;;; -- If :Unknown, then the result values are pushed on the stack, and the
+;;;    result values are specified by the Start and Count as in the
+;;;    unknown-values continuation representation.
+;;; -- If :Tail, then do a tail-recursive call.  No values are returned.
+;;;    The Old-Fp and Return-PC are passed as the second and third arguments.
+;;;
+;;; In non-tail calls, the pointer to the stack arguments is passed as the last
+;;; fixed argument.  If Variable is false, then the passing locations are
+;;; passed as a more arg.  Variable is true if there are a variable number of
+;;; arguments passed on the stack.  Variable cannot be specified with :Tail
+;;; return.  TR variable argument call is implemented separately.
+;;;
+;;; In tail call with fixed arguments, the passing locations are passed as a
+;;; more arg, but there is no new-FP, since the arguments have been set up in
+;;; the current frame.
+(defmacro define-full-call (name named return variable)
+  (assert (not (and variable (eq return :tail))))
+  `(define-vop (,name
+               ,@(when (eq return :unknown)
+                   '(unknown-values-receiver)))
+     (:args
+      ,@(unless (eq return :tail)
+         '((new-fp :scs (any-reg) :to :eval)))
+
+      ,(if named
+          '(name :target name-pass)
+          '(arg-fun :target lexenv))
+      
+      ,@(when (eq return :tail)
+         '((old-fp :target old-fp-pass)
+           (return-pc :target return-pc-pass)))
+      
+      ,@(unless variable '((args :more t :scs (descriptor-reg)))))
+
+     ,@(when (eq return :fixed)
+        '((:results (values :more t))))
+   
+     (:save-p ,(if (eq return :tail) :compute-only t))
+
+     ,@(unless (or (eq return :tail) variable)
+        '((:move-args :full-call)))
+
+     (:vop-var vop)
+     (:info ,@(unless (or variable (eq return :tail)) '(arg-locs))
+           ,@(unless variable '(nargs))
+           ,@(when (eq return :fixed) '(nvals)))
+
+     (:ignore
+      ,@(unless (or variable (eq return :tail)) '(arg-locs))
+      ,@(unless variable '(args)))
+
+     (:temporary (:sc descriptor-reg
+                 :offset ocfp-offset
+                 :from (:argument 1)
+                 ,@(unless (eq return :fixed)
+                     '(:to :eval)))
+                old-fp-pass)
+
+     (:temporary (:sc descriptor-reg
+                 :offset lra-offset
+                 :from (:argument ,(if (eq return :tail) 2 1))
+                 :to :eval)
+                return-pc-pass)
+
+     ,(if named
+         `(:temporary (:sc descriptor-reg :offset cname-offset
+                           :from (:argument ,(if (eq return :tail) 0 1))
+                           :to :eval)
+                      name-pass)
+         `(:temporary (:sc descriptor-reg :offset lexenv-offset
+                           :from (:argument ,(if (eq return :tail) 0 1))
+                           :to :eval)
+                      lexenv))
+
+     (:temporary (:scs (descriptor-reg) :from (:argument 0) :to :eval)
+                function)
+     (:temporary (:sc any-reg :offset nargs-offset :to :eval)
+                nargs-pass)
+
+     ,@(when variable
+        (mapcar #'(lambda (name offset)
+                    `(:temporary (:sc descriptor-reg
+                                  :offset ,offset
+                                  :to :eval)
+                        ,name))
+                register-arg-names *register-arg-offsets*))
+     ,@(when (eq return :fixed)
+        '((:temporary (:scs (descriptor-reg) :from :eval) move-temp)))
+
+     ,@(unless (eq return :tail)
+        '((:temporary (:scs (non-descriptor-reg)) temp)
+          (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)))
+
+     (:generator ,(+ (if named 5 0)
+                    (if variable 19 1)
+                    (if (eq return :tail) 0 10)
+                    15
+                    (if (eq return :unknown) 25 0))
+       (trace-table-entry trace-table-call-site)
+       (let* ((cur-nfp (current-nfp-tn vop))
+             ,@(unless (eq return :tail)
+                 '((lra-label (gen-label))))
+             (filler
+              (remove nil
+                      (list :load-nargs
+                            ,@(if (eq return :tail)
+                                  '((unless (location= old-fp old-fp-pass)
+                                      :load-old-fp)
+                                    (unless (location= return-pc
+                                                       return-pc-pass)
+                                      :load-return-pc)
+                                    (when cur-nfp
+                                      :frob-nfp))
+                                  '(:comp-lra
+                                    (when cur-nfp
+                                      :frob-nfp)
+                                    :save-fp
+                                    :load-fp))))))
+        (flet ((do-next-filler ()
+                 (let* ((next (pop filler))
+                        (what (if (consp next) (car next) next)))
+                   (ecase what
+                     (:load-nargs
+                      ,@(if variable
+                            `((inst sub nargs-pass csp-tn new-fp)
+                              ,@(let ((index -1))
+                                  (mapcar #'(lambda (name)
+                                              `(loadw ,name new-fp
+                                                      ,(incf index)))
+                                          register-arg-names)))
+                            '((inst li nargs-pass (fixnumize nargs)))))
+                     ,@(if (eq return :tail)
+                           '((:load-old-fp
+                              (sc-case old-fp
+                                (any-reg
+                                 (inst move old-fp-pass old-fp))
+                                (control-stack
+                                 (loadw old-fp-pass cfp-tn
+                                        (tn-offset old-fp)))))
+                             (:load-return-pc
+                              (sc-case return-pc
+                                (descriptor-reg
+                                 (inst move return-pc-pass return-pc))
+                                (control-stack
+                                 (loadw return-pc-pass cfp-tn
+                                        (tn-offset return-pc)))))
+                             (:frob-nfp
+                              (inst add nsp-tn cur-nfp
+                                    (- (bytes-needed-for-non-descriptor-stack-frame)
+                                       number-stack-displacement))))
+                           `((:comp-lra
+                              (inst compute-lra-from-code
+                                    return-pc-pass code-tn lra-label temp))
+                             (:frob-nfp
+                              (store-stack-tn nfp-save cur-nfp))
+                             (:save-fp
+                              (inst move old-fp-pass cfp-tn))
+                             (:load-fp
+                              ,(if variable
+                                   '(move cfp-tn new-fp)
+                                   '(if (> nargs register-arg-count)
+                                        (move cfp-tn new-fp)
+                                        (move cfp-tn csp-tn))))))
+                     ((nil))))))
+
+          ,@(if named
+                `((sc-case name
+                    (descriptor-reg (move name-pass name))
+                    (control-stack
+                     (loadw name-pass cfp-tn (tn-offset name))
+                     (do-next-filler))
+                    (constant
+                     (loadw name-pass code-tn (tn-offset name)
+                            other-pointer-lowtag)
+                     (do-next-filler)))
+                  (loadw function name-pass fdefn-raw-addr-slot
+                         other-pointer-lowtag)
+                  (do-next-filler))
+                `((sc-case arg-fun
+                    (descriptor-reg (move lexenv arg-fun))
+                    (control-stack
+                     (loadw lexenv cfp-tn (tn-offset arg-fun))
+                     (do-next-filler))
+                    (constant
+                     (loadw lexenv code-tn (tn-offset arg-fun)
+                            other-pointer-lowtag)
+                     (do-next-filler)))
+                  (loadw function lexenv closure-fun-slot
+                         fun-pointer-lowtag)
+                  (do-next-filler)))
+          (loop
+            (if filler
+                (do-next-filler)
+                (return)))
+          
+          (note-this-location vop :call-site)
+          (inst j function
+                (- (ash simple-fun-code-offset word-shift)
+                   fun-pointer-lowtag))
+          (inst move code-tn function))
+
+        ,@(ecase return
+            (:fixed
+             '((emit-return-pc lra-label)
+               (default-unknown-values vop values nvals move-temp
+                                       temp lra-label)
+               (when cur-nfp
+                 (load-stack-tn cur-nfp nfp-save))))
+            (:unknown
+             '((emit-return-pc lra-label)
+               (note-this-location vop :unknown-return)
+               (receive-unknown-values values-start nvals start count
+                                       lra-label temp)
+               (when cur-nfp
+                 (load-stack-tn cur-nfp nfp-save))))
+            (:tail)))
+       (trace-table-entry trace-table-normal))))
+
+
+(define-full-call call nil :fixed nil)
+(define-full-call call-named t :fixed nil)
+(define-full-call multiple-call nil :unknown nil)
+(define-full-call multiple-call-named t :unknown nil)
+(define-full-call tail-call nil :tail nil)
+(define-full-call tail-call-named t :tail nil)
+
+(define-full-call call-variable nil :fixed t)
+(define-full-call multiple-call-variable nil :unknown t)
+
+
+;;; Defined separately, since needs special code that BLT's the
+;;; arguments down.
+(define-vop (tail-call-variable)
+  (:args
+   (args-arg :scs (any-reg) :target args)
+   (function-arg :scs (descriptor-reg) :target lexenv)
+   (old-fp-arg :scs (any-reg) :target old-fp)
+   (lra-arg :scs (descriptor-reg) :target lra))
+
+  (:temporary (:sc any-reg :offset nl0-offset :from (:argument 0)) args)
+  (:temporary (:sc any-reg :offset lexenv-offset :from (:argument 1)) lexenv)
+  (:temporary (:sc any-reg :offset ocfp-offset :from (:argument 2)) old-fp)
+  (:temporary (:sc any-reg :offset lra-offset :from (:argument 3)) lra)
+
+  (:temporary (:scs (any-reg) :from :eval) temp)
+
+  (:vop-var vop)
+
+  (:generator 75
+
+    ;; Move these into the passing locations if they are not already there.
+    (move args args-arg)
+    (move lexenv function-arg)
+    (move old-fp old-fp-arg)
+    (move lra lra-arg)
+
+    ;; Clear the number stack if anything is there.
+    (let ((cur-nfp (current-nfp-tn vop)))
+      (when cur-nfp
+       (inst add nsp-tn cur-nfp
+             (- (bytes-needed-for-non-descriptor-stack-frame)
+                number-stack-displacement))))
+
+    ;; And jump to the assembly-routine that does the bliting.
+    (inst ji temp (make-fixup 'tail-call-variable :assembly-routine))
+    (inst nop)))
+
+\f
+;;;; Unknown values return:
+
+
+;;; Return a single value using the unknown-values convention.
+(define-vop (return-single)
+  (:args (old-fp :scs (any-reg))
+        (return-pc :scs (descriptor-reg))
+        (value))
+  (:ignore value)
+  (:vop-var vop)
+  (:generator 6
+    (trace-table-entry trace-table-fun-epilogue)
+    ;; Clear the number stack.
+    (let ((cur-nfp (current-nfp-tn vop)))
+      (when cur-nfp
+       (inst add nsp-tn cur-nfp
+             (- (bytes-needed-for-non-descriptor-stack-frame)
+                number-stack-displacement))))
+    ;; Clear the control stack, and restore the frame pointer.
+    (move csp-tn cfp-tn)
+    (move cfp-tn old-fp)
+    ;; Out of here.
+    (lisp-return return-pc :offset 2)
+    (trace-table-entry trace-table-normal)))
+
+;;; Do unknown-values return of a fixed number of values.  The Values are
+;;; required to be set up in the standard passing locations.  Nvals is the
+;;; number of values returned.
+;;;
+;;; If returning a single value, then deallocate the current frame, restore
+;;; FP and jump to the single-value entry at Return-PC + 8.
+;;;
+;;; If returning other than one value, then load the number of values returned,
+;;; NIL out unsupplied values registers, restore FP and return at Return-PC.
+;;; When there are stack values, we must initialize the argument pointer to
+;;; point to the beginning of the values block (which is the beginning of the
+;;; current frame.)
+(define-vop (return)
+  (:args
+   (old-fp :scs (any-reg))
+   (return-pc :scs (descriptor-reg) :to (:eval 1))
+   (values :more t))
+  (:ignore values)
+  (:info nvals)
+  (:temporary (:sc descriptor-reg :offset a0-offset :from (:eval 0)) a0)
+  (:temporary (:sc descriptor-reg :offset a1-offset :from (:eval 0)) a1)
+  (:temporary (:sc descriptor-reg :offset a2-offset :from (:eval 0)) a2)
+  (:temporary (:sc descriptor-reg :offset a3-offset :from (:eval 0)) a3)
+  (:temporary (:sc descriptor-reg :offset a4-offset :from (:eval 0)) a4)
+  (:temporary (:sc descriptor-reg :offset a5-offset :from (:eval 0)) a5)
+  (:temporary (:sc any-reg :offset nargs-offset) nargs)
+  (:temporary (:sc any-reg :offset ocfp-offset) val-ptr)
+  (:vop-var vop)
+  (:generator 6
+    (trace-table-entry trace-table-fun-epilogue)
+    ;; Clear the number stack.
+    (let ((cur-nfp (current-nfp-tn vop)))
+      (when cur-nfp
+       (inst add nsp-tn cur-nfp
+             (- (bytes-needed-for-non-descriptor-stack-frame)
+                number-stack-displacement))))
+    (cond ((= nvals 1)
+          ;; Clear the control stack, and restore the frame pointer.
+          (move csp-tn cfp-tn)
+          (move cfp-tn old-fp)
+          ;; Out of here.
+          (lisp-return return-pc :offset 2))
+         (t
+          ;; Establish the values pointer and values count.
+          (move val-ptr cfp-tn)
+          (inst li nargs (fixnumize nvals))
+          ;; restore the frame pointer and clear as much of the control
+          ;; stack as possible.
+          (move cfp-tn old-fp)
+          (inst add csp-tn val-ptr (* nvals n-word-bytes))
+          ;; pre-default any argument register that need it.
+          (when (< nvals register-arg-count)
+            (dolist (reg (subseq (list a0 a1 a2 a3 a4 a5) nvals))
+              (move reg null-tn)))
+          ;; And away we go.
+          (lisp-return return-pc)))
+    (trace-table-entry trace-table-normal)))
+
+;;; Do unknown-values return of an arbitrary number of values (passed on the
+;;; stack.)  We check for the common case of a single return value, and do that
+;;; inline using the normal single value return convention.  Otherwise, we
+;;; branch off to code that calls an assembly-routine.
+(define-vop (return-multiple)
+  (:args
+   (old-fp-arg :scs (any-reg) :to (:eval 1))
+   (lra-arg :scs (descriptor-reg) :to (:eval 1))
+   (vals-arg :scs (any-reg) :target vals)
+   (nvals-arg :scs (any-reg) :target nvals))
+
+  (:temporary (:sc any-reg :offset nl1-offset :from (:argument 0)) old-fp)
+  (:temporary (:sc descriptor-reg :offset lra-offset :from (:argument 1)) lra)
+  (:temporary (:sc any-reg :offset nl0-offset :from (:argument 2)) vals)
+  (:temporary (:sc any-reg :offset nargs-offset :from (:argument 3)) nvals)
+  (:temporary (:sc descriptor-reg :offset a0-offset) a0)
+
+  (:temporary (:scs (any-reg) :from (:eval 1)) temp)
+
+  (:vop-var vop)
+
+  (:generator 13
+    (trace-table-entry trace-table-fun-epilogue)
+    (let ((not-single (gen-label)))
+      ;; Clear the number stack.
+      (let ((cur-nfp (current-nfp-tn vop)))
+       (when cur-nfp
+         (inst add nsp-tn cur-nfp
+               (- (bytes-needed-for-non-descriptor-stack-frame)
+                  number-stack-displacement))))
+
+      ;; Check for the single case.
+      (inst cmp nvals-arg (fixnumize 1))
+      (inst b :ne not-single)
+      (inst ld a0 vals-arg)
+
+      ;; Return with one value.
+      (move csp-tn cfp-tn)
+      (move cfp-tn old-fp-arg)
+      (lisp-return lra-arg :offset 2)
+               
+      ;; Nope, not the single case.
+      (emit-label not-single)
+      (move old-fp old-fp-arg)
+      (move lra lra-arg)
+      (move vals vals-arg)
+      (move nvals nvals-arg)
+      (inst ji temp (make-fixup 'return-multiple :assembly-routine))
+      (inst nop))
+    (trace-table-entry trace-table-normal)))
+
+
+\f
+;;;; XEP hackery:
+
+
+;;; We don't need to do anything special for regular functions.
+(define-vop (setup-environment)
+  (:info label)
+  (:ignore label)
+  (:generator 0
+    ;; Don't bother doing anything.
+    ))
+
+;;; Get the lexical environment from it's passing location.
+(define-vop (setup-closure-environment)
+  (:temporary (:sc descriptor-reg :offset lexenv-offset :target closure
+              :to (:result 0))
+             lexenv)
+  (:results (closure :scs (descriptor-reg)))
+  (:info label)
+  (:ignore label)
+  (:generator 6
+    ;; Get result.
+    (move closure lexenv)))
+
+;;; Copy a more arg from the argument area to the end of the current frame.
+;;; Fixed is the number of non-more arguments. 
+(define-vop (copy-more-arg)
+  (:temporary (:sc any-reg :offset nl0-offset) result)
+  (:temporary (:sc any-reg :offset nl1-offset) count)
+  (:temporary (:sc any-reg :offset nl2-offset) src)
+  (:temporary (:sc any-reg :offset nl3-offset) dst)
+  (:temporary (:sc descriptor-reg :offset l0-offset) temp)
+  (:info fixed)
+  (:generator 20
+    (let ((loop (gen-label))
+         (do-regs (gen-label))
+         (done (gen-label)))
+      (when (< fixed register-arg-count)
+       ;; Save a pointer to the results so we can fill in register args.
+       ;; We don't need this if there are more fixed args than reg args.
+       (move result csp-tn))
+      ;; Allocate the space on the stack.
+      (cond ((zerop fixed)
+            (inst cmp nargs-tn)
+            (inst b :eq done)
+            (inst add csp-tn csp-tn nargs-tn))
+           (t
+            (inst subcc count nargs-tn (fixnumize fixed))
+            (inst b :le done)
+            (inst nop)
+            (inst add csp-tn csp-tn count)))
+      (when (< fixed register-arg-count)
+       ;; We must stop when we run out of stack args, not when we run out of
+       ;; more args.
+       (inst subcc count nargs-tn (fixnumize register-arg-count))
+       ;; Everything of interest in registers.
+       (inst b :le do-regs))
+      ;; Initialize dst to be end of stack.
+      (move dst csp-tn)
+      ;; Initialize src to be end of args.
+      (inst add src cfp-tn nargs-tn)
+
+      (emit-label loop)
+      ;; *--dst = *--src, --count
+      (inst add src src (- n-word-bytes))
+      (inst subcc count count (fixnumize 1))
+      (loadw temp src)
+      (inst add dst dst (- n-word-bytes))
+      (inst b :gt loop)
+      (storew temp dst)
+
+      (emit-label do-regs)
+      (when (< fixed register-arg-count)
+       ;; Now we have to deposit any more args that showed up in registers.
+       (inst subcc count nargs-tn (fixnumize fixed))
+       (do ((i fixed (1+ i)))
+           ((>= i register-arg-count))
+         ;; Don't deposit any more than there are.
+         (inst b :eq done)
+         (inst subcc count (fixnumize 1))
+         ;; Store it relative to the pointer saved at the start.
+         (storew (nth i *register-arg-tns*) result (- i fixed))))
+      (emit-label done))))
+
+
+;;; More args are stored consequtively on the stack, starting immediately at
+;;; the context pointer.  The context pointer is not typed, so the lowtag is 0.
+(define-vop (more-arg word-index-ref)
+  (:variant 0 0)
+  (:translate %more-arg))
+
+
+;;; Turn more arg (context, count) into a list.
+(define-vop (listify-rest-args)
+  (:args (context-arg :target context :scs (descriptor-reg))
+        (count-arg :target count :scs (any-reg)))
+  (:arg-types * tagged-num)
+  (:temporary (:scs (any-reg) :from (:argument 0)) context)
+  (:temporary (:scs (any-reg) :from (:argument 1)) count)
+  (:temporary (:scs (descriptor-reg) :from :eval) temp)
+  (:temporary (:scs (non-descriptor-reg) :from :eval) dst)
+  (:results (result :scs (descriptor-reg)))
+  (:translate %listify-rest-args)
+  (:policy :safe)
+  (:generator 20
+    (move context context-arg)
+    (move count count-arg)
+    ;; Check to see if there are any arguments.
+    (inst cmp count)
+    (inst b :eq done)
+    (move result null-tn)
+
+    ;; We need to do this atomically.
+    (pseudo-atomic ()
+      (assemble ()
+       ;; Allocate a cons (2 words) for each item.
+       (inst andn result alloc-tn lowtag-mask)
+       (inst or result list-pointer-lowtag)
+       (move dst result)
+       (inst sll temp count 1)
+       (inst b enter)
+       (inst add alloc-tn temp)
+
+       ;; Compute the next cons and store it in the current one.
+       LOOP
+       (inst add dst dst (* 2 n-word-bytes))
+       (storew dst dst -1 list-pointer-lowtag)
+
+       ;; Grab one value.
+       ENTER
+       (loadw temp context)
+       (inst add context context n-word-bytes)
+
+       ;; Dec count, and if != zero, go back for more.
+       (inst subcc count (fixnumize 1))
+       (inst b :gt loop)
+
+       ;; Store the value into the car of the current cons (in the delay
+       ;; slot).
+       (storew temp dst 0 list-pointer-lowtag)
+
+       ;; NIL out the last cons.
+       (storew null-tn dst 1 list-pointer-lowtag)))
+    DONE))
+
+
+;;; Return the location and size of the more arg glob created by Copy-More-Arg.
+;;; Supplied is the total number of arguments supplied (originally passed in
+;;; NARGS.)  Fixed is the number of non-rest arguments.
+;;;
+;;; We must duplicate some of the work done by Copy-More-Arg, since at that
+;;; time the environment is in a pretty brain-damaged state, preventing this
+;;; info from being returned as values.  What we do is compute
+;;; supplied - fixed, and return a pointer that many words below the current
+;;; stack top.
+(define-vop (more-arg-context)
+  (:policy :fast-safe)
+  (:translate sb!c::%more-arg-context)
+  (:args (supplied :scs (any-reg)))
+  (:arg-types tagged-num (:constant fixnum))
+  (:info fixed)
+  (:results (context :scs (descriptor-reg))
+           (count :scs (any-reg)))
+  (:result-types t tagged-num)
+  (:note "more-arg-context")
+  (:generator 5
+    (inst sub count supplied (fixnumize fixed))
+    (inst sub context csp-tn count)))
+
+
+;;; Signal wrong argument count error if Nargs isn't = to Count.
+;;;
+(define-vop (verify-arg-count)
+  (:policy :fast-safe)
+  (:translate sb!c::%verify-arg-count)
+  (:args (nargs :scs (any-reg)))
+  (:arg-types positive-fixnum (:constant t))
+  (:info count)
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:generator 3
+    (let ((err-lab
+          (generate-error-code vop invalid-arg-count-error nargs)))
+      (inst cmp nargs (fixnumize count))
+      ;; Assume we don't take the branch
+      (inst b :ne err-lab #!+sparc-v9 :pn)
+      (inst nop))))
+
+;;; Signal various errors.
+(macrolet ((frob (name error translate &rest args)
+            `(define-vop (,name)
+               ,@(when translate
+                   `((:policy :fast-safe)
+                     (:translate ,translate)))
+               (:args ,@(mapcar #'(lambda (arg)
+                                    `(,arg :scs (any-reg descriptor-reg)))
+                                args))
+               (:vop-var vop)
+               (:save-p :compute-only)
+               (:generator 1000
+                 (error-call vop ,error ,@args)))))
+  (frob arg-count-error invalid-arg-count-error
+    sb!c::%arg-count-error nargs)
+  (frob type-check-error object-not-type-error sb!c::%type-check-error
+    object type)
+  (frob layout-invalid-error layout-invalid-error sb!c::%layout-invalid-error
+    object layout)
+  (frob odd-key-args-error odd-key-args-error
+    sb!c::%odd-key-args-error)
+  (frob unknown-key-arg-error unknown-key-arg-error
+    sb!c::%unknown-key-arg-error key)
+  (frob nil-fun-returned-error nil-fun-returned-error nil fun))
diff --git a/src/compiler/sparc/cell.lisp b/src/compiler/sparc/cell.lisp
new file mode 100644 (file)
index 0000000..2d632bc
--- /dev/null
@@ -0,0 +1,276 @@
+;;;; the VM definition of various primitive memory access VOPs for the
+;;;; Sparc
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; data object ref/set stuff.
+(define-vop (slot)
+  (:args (object :scs (descriptor-reg)))
+  (:info name offset lowtag)
+  (:ignore name)
+  (:results (result :scs (descriptor-reg any-reg)))
+  (:generator 1
+    (loadw result object offset lowtag)))
+
+(define-vop (set-slot)
+  (:args (object :scs (descriptor-reg))
+        (value :scs (descriptor-reg any-reg)))
+  (:info name offset lowtag)
+  (:ignore name)
+  (:results)
+  (:generator 1
+    (storew value object offset lowtag)))
+\f
+;;;; Symbol hacking VOPs:
+
+;;; The compiler likes to be able to directly SET symbols.
+(define-vop (set cell-set)
+  (:variant symbol-value-slot other-pointer-lowtag))
+
+;;; Do a cell ref with an error check for being unbound.
+(define-vop (checked-cell-ref)
+  (:args (object :scs (descriptor-reg) :target obj-temp))
+  (:results (value :scs (descriptor-reg any-reg)))
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:temporary (:scs (descriptor-reg) :from (:argument 0)) obj-temp))
+
+;;; With Symbol-Value, we check that the value isn't the trap object.
+;;; So Symbol-Value of NIL is NIL.
+(define-vop (symbol-value checked-cell-ref)
+  (:translate symbol-value)
+  (:generator 9
+    (move obj-temp object)
+    (loadw value obj-temp symbol-value-slot other-pointer-lowtag)
+    (let ((err-lab (generate-error-code vop unbound-symbol-error obj-temp)))
+      (inst cmp value unbound-marker-widetag)
+      (inst b :eq err-lab)
+      (inst nop))))
+
+;;; Like CHECKED-CELL-REF, only we are a predicate to see if the cell
+;;; is bound.
+(define-vop (boundp-frob)
+  (:args (object :scs (descriptor-reg)))
+  (:conditional)
+  (:info target not-p)
+  (:policy :fast-safe)
+  (:temporary (:scs (descriptor-reg)) value))
+
+(define-vop (boundp boundp-frob)
+  (:translate boundp)
+  (:generator 9
+    (loadw value object symbol-value-slot other-pointer-lowtag)
+    (inst cmp value unbound-marker-widetag)
+    (inst b (if not-p :eq :ne) target)
+    (inst nop)))
+
+(define-vop (fast-symbol-value cell-ref)
+  (:variant symbol-value-slot other-pointer-lowtag)
+  (:policy :fast)
+  (:translate symbol-value))
+
+\f
+;;;; FDEFINITION (fdefn) objects.
+(define-vop (fdefn-fun cell-ref)
+  (:variant fdefn-fun-slot other-pointer-lowtag))
+
+(define-vop (safe-fdefn-fun)
+  (:args (object :scs (descriptor-reg) :target obj-temp))
+  (:results (value :scs (descriptor-reg any-reg)))
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:temporary (:scs (descriptor-reg) :from (:argument 0)) obj-temp)
+  (:generator 10
+    (move obj-temp object)
+    (loadw value obj-temp fdefn-fun-slot other-pointer-lowtag)
+    (inst cmp value null-tn)
+    (let ((err-lab (generate-error-code vop undefined-symbol-error obj-temp)))
+      (inst b :eq err-lab))
+    (inst nop)))
+
+(define-vop (set-fdefn-fun)
+  (:policy :fast-safe)
+  (:translate (setf fdefn-fun))
+  (:args (function :scs (descriptor-reg) :target result)
+        (fdefn :scs (descriptor-reg)))
+  (:temporary (:scs (interior-reg)) lip)
+  (:temporary (:scs (non-descriptor-reg)) type)
+  (:results (result :scs (descriptor-reg)))
+  (:generator 38
+    (let ((normal-fn (gen-label)))
+      (load-type type function (- fun-pointer-lowtag))
+      (inst cmp type simple-fun-header-widetag)
+      (inst b :eq normal-fn)
+      (inst move lip function)
+      (inst li lip (make-fixup (extern-alien-name "closure_tramp") :foreign))
+      (emit-label normal-fn)
+      (storew function fdefn fdefn-fun-slot other-pointer-lowtag)
+      (storew lip fdefn fdefn-raw-addr-slot other-pointer-lowtag)
+      (move result function))))
+
+(define-vop (fdefn-makunbound)
+  (:policy :fast-safe)
+  (:translate fdefn-makunbound)
+  (:args (fdefn :scs (descriptor-reg) :target result))
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:results (result :scs (descriptor-reg)))
+  (:generator 38
+    (storew null-tn fdefn fdefn-fun-slot other-pointer-lowtag)
+    (inst li temp (make-fixup (extern-alien-name "undefined_tramp") :foreign))
+    (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag)
+    (move result fdefn)))
+
+
+\f
+;;;; Binding and Unbinding.
+
+;;; Establish VAL as a binding for SYMBOL.  Save the old value and the
+;;; symbol on the binding stack and stuff the new value into the
+;;; symbol.
+(define-vop (bind)
+  (:args (val :scs (any-reg descriptor-reg))
+        (symbol :scs (descriptor-reg)))
+  (:temporary (:scs (descriptor-reg)) temp)
+  (:generator 5
+    (loadw temp symbol symbol-value-slot other-pointer-lowtag)
+    (inst add bsp-tn bsp-tn (* 2 n-word-bytes))
+    (storew temp bsp-tn (- binding-value-slot binding-size))
+    (storew symbol bsp-tn (- binding-symbol-slot binding-size))
+    (storew val symbol symbol-value-slot other-pointer-lowtag)))
+
+(define-vop (unbind)
+  (:temporary (:scs (descriptor-reg)) symbol value)
+  (:generator 0
+    (loadw symbol bsp-tn (- binding-symbol-slot binding-size))
+    (loadw value bsp-tn (- binding-value-slot binding-size))
+    (storew value symbol symbol-value-slot other-pointer-lowtag)
+    (storew zero-tn bsp-tn (- binding-symbol-slot binding-size))
+    (inst sub bsp-tn bsp-tn (* 2 n-word-bytes))))
+
+(define-vop (unbind-to-here)
+  (:args (arg :scs (descriptor-reg any-reg) :target where))
+  (:temporary (:scs (any-reg) :from (:argument 0)) where)
+  (:temporary (:scs (descriptor-reg)) symbol value)
+  (:generator 0
+    (let ((loop (gen-label))
+         (skip (gen-label))
+         (done (gen-label)))
+      (move where arg)
+      (inst cmp where bsp-tn)
+      (inst b :eq done)
+      (inst nop)
+
+      (emit-label loop)
+      (loadw symbol bsp-tn (- binding-symbol-slot binding-size))
+      (inst cmp symbol)
+      (inst b :eq skip)
+      (loadw value bsp-tn (- binding-value-slot binding-size))
+      (storew value symbol symbol-value-slot other-pointer-lowtag)
+      (storew zero-tn bsp-tn (- binding-symbol-slot binding-size))
+
+      (emit-label skip)
+      (inst sub bsp-tn bsp-tn (* 2 n-word-bytes))
+      (inst cmp where bsp-tn)
+      (inst b :ne loop)
+      (inst nop)
+
+      (emit-label done))))
+\f
+;;;; closure indexing.
+
+(define-vop (closure-index-ref word-index-ref)
+  (:variant closure-info-offset fun-pointer-lowtag)
+  (:translate %closure-index-ref))
+
+(define-vop (funcallable-instance-info word-index-ref)
+  (:variant funcallable-instance-info-offset fun-pointer-lowtag)
+  (:translate %funcallable-instance-info))
+
+(define-vop (set-funcallable-instance-info word-index-set)
+  (:variant funcallable-instance-info-offset fun-pointer-lowtag)
+  (:translate %set-funcallable-instance-info))
+
+(define-vop (funcallable-instance-lexenv cell-ref)
+  (:variant funcallable-instance-lexenv-slot fun-pointer-lowtag))
+
+
+(define-vop (closure-ref slot-ref)
+  (:variant closure-info-offset fun-pointer-lowtag))
+
+(define-vop (closure-init slot-set)
+  (:variant closure-info-offset fun-pointer-lowtag))
+\f
+;;;; value cell hackery.
+
+(define-vop (value-cell-ref cell-ref)
+  (:variant value-cell-value-slot other-pointer-lowtag))
+
+(define-vop (value-cell-set cell-set)
+  (:variant value-cell-value-slot other-pointer-lowtag))
+\f
+;;;; instance hackery:
+
+(define-vop (instance-length)
+  (:policy :fast-safe)
+  (:translate %instance-length)
+  (:args (struct :scs (descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:results (res :scs (unsigned-reg)))
+  (:result-types positive-fixnum)
+  (:generator 4
+    (loadw temp struct 0 instance-pointer-lowtag)
+    (inst srl res temp n-widetag-bits)))
+
+(define-vop (instance-ref slot-ref)
+  (:variant instance-slots-offset instance-pointer-lowtag)
+  (:policy :fast-safe)
+  (:translate %instance-ref)
+  (:arg-types * (:constant index)))
+
+;;; This VOP has no :results; however, %instance-set must return a
+;;; value. This caused, in the forward port to 0.7.x, an error in
+;;; !fdefn-cold-init: "argument X is not a REAL: NIL". This VOP is
+;;; commented out for now, pending the addition of checking code to
+;;; the define-vop machinery to ascertain that this was indeed the
+;;; problem. -- CSR, 2002-02-12
+#+nil
+(define-vop (instance-set slot-set)
+  (:policy :fast-safe)
+  (:translate %instance-set)
+  (:variant instance-slots-offset instance-pointer-lowtag)
+  (:arg-types * (:constant index) *))
+
+(define-vop (instance-index-ref word-index-ref)
+  (:policy :fast-safe) 
+  (:translate %instance-ref)
+  (:variant instance-slots-offset instance-pointer-lowtag)
+  (:arg-types * positive-fixnum))
+
+(define-vop (instance-index-set word-index-set)
+  (:policy :fast-safe) 
+  (:translate %instance-set)
+  (:variant instance-slots-offset instance-pointer-lowtag)
+  (:arg-types * positive-fixnum *))
+\f
+;;;; Code object frobbing.
+
+(define-vop (code-header-ref word-index-ref)
+  (:translate code-header-ref)
+  (:policy :fast-safe)
+  (:variant 0 other-pointer-lowtag))
+
+(define-vop (code-header-set word-index-set)
+  (:translate code-header-set)
+  (:policy :fast-safe)
+  (:variant 0 other-pointer-lowtag))
+
diff --git a/src/compiler/sparc/char.lisp b/src/compiler/sparc/char.lisp
new file mode 100644 (file)
index 0000000..bce3b41
--- /dev/null
@@ -0,0 +1,131 @@
+;;;; the Sparc VM definition of character operations
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; moves and coercions:
+
+;;; Move a tagged char to an untagged representation.
+(define-vop (move-to-base-char)
+  (:args (x :scs (any-reg descriptor-reg)))
+  (:results (y :scs (base-char-reg)))
+  (:note "character untagging")
+  (:generator 1
+    (inst srl y x n-widetag-bits)))
+
+(define-move-vop move-to-base-char :move
+  (any-reg descriptor-reg) (base-char-reg))
+
+
+;;; Move an untagged char to a tagged representation.
+(define-vop (move-from-base-char)
+  (:args (x :scs (base-char-reg)))
+  (:results (y :scs (any-reg descriptor-reg)))
+  (:note "character tagging")
+  (:generator 1
+    (inst sll y x n-widetag-bits)
+    (inst or y base-char-widetag)))
+
+(define-move-vop move-from-base-char :move
+  (base-char-reg) (any-reg descriptor-reg))
+
+;;; Move untagged base-char values.
+(define-vop (base-char-move)
+  (:args (x :target y
+           :scs (base-char-reg)
+           :load-if (not (location= x y))))
+  (:results (y :scs (base-char-reg)
+              :load-if (not (location= x y))))
+  (:note "character move")
+  (:effects)
+  (:affected)
+  (:generator 0
+    (move y x)))
+
+(define-move-vop base-char-move :move
+  (base-char-reg) (base-char-reg))
+
+
+;;; Move untagged base-char arguments/return-values.
+(define-vop (move-base-char-arg)
+  (:args (x :target y
+           :scs (base-char-reg))
+        (fp :scs (any-reg)
+            :load-if (not (sc-is y base-char-reg))))
+  (:results (y))
+  (:note "character arg move")
+  (:generator 0
+    (sc-case y
+      (base-char-reg
+       (move y x))
+      (base-char-stack
+       (storew x fp (tn-offset y))))))
+
+(define-move-vop move-base-char-arg :move-arg
+  (any-reg base-char-reg) (base-char-reg))
+
+
+;;; Use standard MOVE-ARG + coercion to move an untagged base-char
+;;; to a descriptor passing location.
+(define-move-vop move-arg :move-arg
+  (base-char-reg) (any-reg descriptor-reg))
+
+
+\f
+;;;; Other operations:
+
+(define-vop (char-code)
+  (:translate char-code)
+  (:policy :fast-safe)
+  (:args (ch :scs (base-char-reg) :target res))
+  (:arg-types base-char)
+  (:results (res :scs (any-reg)))
+  (:result-types positive-fixnum)
+  (:generator 1
+    (inst sll res ch fixnum-tag-bits)))
+
+(define-vop (code-char)
+  (:translate code-char)
+  (:policy :fast-safe)
+  (:args (code :scs (any-reg) :target res))
+  (:arg-types positive-fixnum)
+  (:results (res :scs (base-char-reg)))
+  (:result-types base-char)
+  (:generator 1
+    (inst srl res code fixnum-tag-bits)))
+
+\f
+;;; Comparison of base-chars.
+(define-vop (base-char-compare)
+  (:args (x :scs (base-char-reg))
+        (y :scs (base-char-reg)))
+  (:arg-types base-char base-char)
+  (:conditional)
+  (:info target not-p)
+  (:policy :fast-safe)
+  (:note "inline comparison")
+  (:variant-vars condition not-condition)
+  (:generator 3
+    (inst cmp x y)
+    (inst b (if not-p not-condition condition) target)
+    (inst nop)))
+
+(define-vop (fast-char=/base-char base-char-compare)
+  (:translate char=)
+  (:variant :eq :ne))
+
+(define-vop (fast-char</base-char base-char-compare)
+  (:translate char<)
+  (:variant :ltu :geu))
+
+(define-vop (fast-char>/base-char base-char-compare)
+  (:translate char>)
+  (:variant :gtu :leu))
diff --git a/src/compiler/sparc/debug.lisp b/src/compiler/sparc/debug.lisp
new file mode 100644 (file)
index 0000000..728fe57
--- /dev/null
@@ -0,0 +1,122 @@
+;;;; Sparc compiler support for the new whizzy debugger
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+;;; (defknown di::current-sp () system-area-pointer (movable flushable))
+;;; (defknown di::current-fp () system-area-pointer (movable flushable))
+;;; (defknown di::stack-ref (system-area-pointer index) t (flushable))
+;;; (defknown di::%set-stack-ref (system-area-pointer index t) t (unsafe))
+;;; (defknown di::lra-code-header (t) t (movable flushable))
+;;; (defknown di::function-code-header (t) t (movable flushable))
+;;; (defknown di::make-lisp-obj ((unsigned-byte 32)) t (movable flushable))
+;;; (defknown di::get-lisp-obj-address (t) (unsigned-byte 32) (movable flushable))
+;;; (defknown di::function-word-offset (function) index (movable flushable))
+
+(define-vop (debug-cur-sp)
+  (:translate current-sp)
+  (:policy :fast-safe)
+  (:results (res :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:generator 1
+    (move res csp-tn)))
+
+(define-vop (debug-cur-fp)
+  (:translate current-fp)
+  (:policy :fast-safe)
+  (:results (res :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:generator 1
+    (move res cfp-tn)))
+
+(define-vop (read-control-stack)
+  (:translate sb!kernel:stack-ref)
+  (:policy :fast-safe)
+  (:args (sap :scs (sap-reg))
+        (offset :scs (any-reg)))
+  (:arg-types system-area-pointer positive-fixnum)
+  (:results (result :scs (descriptor-reg)))
+  (:result-types *)
+  (:generator 5
+    (inst ld result sap offset)))
+
+(define-vop (write-control-stack)
+  (:translate sb!kernel:%set-stack-ref)
+  (:policy :fast-safe)
+  (:args (sap :scs (sap-reg))
+        (offset :scs (any-reg))
+        (value :scs (descriptor-reg) :target result))
+  (:arg-types system-area-pointer positive-fixnum *)
+  (:results (result :scs (descriptor-reg)))
+  (:result-types *)
+  (:generator 5
+    (inst st value sap offset)
+    (move result value)))
+
+(define-vop (code-from-mumble)
+  (:policy :fast-safe)
+  (:args (thing :scs (descriptor-reg)))
+  (:results (code :scs (descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:variant-vars lowtag)
+  (:generator 5
+    (let ((bogus (gen-label))
+         (done (gen-label)))
+      (loadw temp thing 0 lowtag)
+      (inst srl temp n-widetag-bits)
+      (inst cmp temp)
+      (inst b :eq bogus)
+      (inst sll temp (1- (integer-length n-word-bytes)))
+      (unless (= lowtag other-pointer-lowtag)
+       (inst add temp (- lowtag other-pointer-lowtag)))
+      (inst sub code thing temp)
+      (emit-label done)
+      (assemble (*elsewhere*)
+       (emit-label bogus)
+       (inst b done)
+       (move code null-tn)))))
+
+(define-vop (code-from-lra code-from-mumble)
+  (:translate lra-code-header)
+  (:variant other-pointer-lowtag))
+
+(define-vop (code-from-function code-from-mumble)
+  (:translate fun-code-header)
+  (:variant fun-pointer-lowtag))
+
+(define-vop (make-lisp-obj)
+  (:policy :fast-safe)
+  (:translate make-lisp-obj)
+  (:args (value :scs (unsigned-reg) :target result))
+  (:arg-types unsigned-num)
+  (:results (result :scs (descriptor-reg)))
+  (:generator 1
+    (move result value)))
+
+(define-vop (get-lisp-obj-address)
+  (:policy :fast-safe)
+  (:translate get-lisp-obj-address)
+  (:args (thing :scs (descriptor-reg) :target result))
+  (:results (result :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:generator 1
+    (move result thing)))
+
+
+(define-vop (fun-word-offset)
+  (:policy :fast-safe)
+  (:translate fun-word-offset)
+  (:args (fun :scs (descriptor-reg)))
+  (:results (res :scs (unsigned-reg)))
+  (:result-types positive-fixnum)
+  (:generator 5
+    (loadw res fun 0 fun-pointer-lowtag)
+    (inst srl res n-widetag-bits)))
diff --git a/src/compiler/sparc/float.lisp b/src/compiler/sparc/float.lisp
new file mode 100644 (file)
index 0000000..ba28bba
--- /dev/null
@@ -0,0 +1,2582 @@
+;;;; floating point support for the Sparc
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; float move functions
+
+(define-move-fun (load-single 1) (vop x y)
+  ((single-stack) (single-reg))
+  (inst ldf y (current-nfp-tn vop) (* (tn-offset x) n-word-bytes)))
+
+(define-move-fun (store-single 1) (vop x y)
+  ((single-reg) (single-stack))
+  (inst stf x (current-nfp-tn vop) (* (tn-offset y) n-word-bytes)))
+
+
+(define-move-fun (load-double 2) (vop x y)
+  ((double-stack) (double-reg))
+  (let ((nfp (current-nfp-tn vop))
+       (offset (* (tn-offset x) n-word-bytes)))
+    (inst lddf y nfp offset)))
+
+(define-move-fun (store-double 2) (vop x y)
+  ((double-reg) (double-stack))
+  (let ((nfp (current-nfp-tn vop))
+       (offset (* (tn-offset y) n-word-bytes)))
+    (inst stdf x nfp offset)))
+
+;;; The offset may be an integer or a TN in which case it will be
+;;; temporarily modified but is restored if restore-offset is true.
+(defun load-long-reg (reg base offset &optional (restore-offset t))
+  #!+:sparc-v9
+  (inst ldqf reg base offset)
+  #!-:sparc-v9
+  (let ((reg0 (make-random-tn :kind :normal
+                             :sc (sc-or-lose 'double-reg)
+                             :offset (tn-offset reg)))
+       (reg2 (make-random-tn :kind :normal
+                             :sc (sc-or-lose 'double-reg)
+                             :offset (+ 2 (tn-offset reg)))))
+    (cond ((integerp offset)
+          (inst lddf reg0 base offset)
+          (inst lddf reg2 base (+ offset (* 2 n-word-bytes))))
+         (t
+          (inst lddf reg0 base offset)
+          (inst add offset (* 2 n-word-bytes))
+          (inst lddf reg2 base offset)
+          (when restore-offset
+            (inst sub offset (* 2 n-word-bytes)))))))
+
+#!+long-float
+(define-move-fun (load-long 2) (vop x y)
+  ((long-stack) (long-reg))
+  (let ((nfp (current-nfp-tn vop))
+       (offset (* (tn-offset x) n-word-bytes)))
+    (load-long-reg y nfp offset)))
+
+;;; The offset may be an integer or a TN in which case it will be
+;;; temporarily modified but is restored if restore-offset is true.
+(defun store-long-reg (reg base offset &optional (restore-offset t))
+  #!+:sparc-v9
+  (inst stqf reg base offset)
+  #!-:sparc-v9
+  (let ((reg0 (make-random-tn :kind :normal
+                             :sc (sc-or-lose 'double-reg)
+                             :offset (tn-offset reg)))
+       (reg2 (make-random-tn :kind :normal
+                             :sc (sc-or-lose 'double-reg)
+                             :offset (+ 2 (tn-offset reg)))))
+    (cond ((integerp offset)
+          (inst stdf reg0 base offset)
+          (inst stdf reg2 base (+ offset (* 2 n-word-bytes))))
+         (t
+          (inst stdf reg0 base offset)
+          (inst add offset (* 2 n-word-bytes))
+          (inst stdf reg2 base offset)
+          (when restore-offset
+            (inst sub offset (* 2 n-word-bytes)))))))
+
+#!+long-float
+(define-move-fun (store-long 2) (vop x y)
+  ((long-reg) (long-stack))
+  (let ((nfp (current-nfp-tn vop))
+       (offset (* (tn-offset y) n-word-bytes)))
+    (store-long-reg x nfp offset)))
+
+\f
+;;;; Move VOPs:
+
+;;; Exploit the V9 double-float move instruction. This is conditional
+;;; on the :sparc-v9 feature.
+(defun move-double-reg (dst src)
+  #!+:sparc-v9
+  (inst fmovd dst src)
+  #!-:sparc-v9
+  (dotimes (i 2)
+    (let ((dst (make-random-tn :kind :normal
+                              :sc (sc-or-lose 'single-reg)
+                              :offset (+ i (tn-offset dst))))
+         (src (make-random-tn :kind :normal
+                              :sc (sc-or-lose 'single-reg)
+                              :offset (+ i (tn-offset src)))))
+      (inst fmovs dst src))))
+
+;;; Exploit the V9 long-float move instruction. This is conditional
+;;; on the :sparc-v9 feature.
+(defun move-long-reg (dst src)
+  #!+:sparc-v9
+  (inst fmovq dst src)
+  #!-:sparc-v9
+  (dotimes (i 4)
+    (let ((dst (make-random-tn :kind :normal
+                              :sc (sc-or-lose 'single-reg)
+                              :offset (+ i (tn-offset dst))))
+         (src (make-random-tn :kind :normal
+                              :sc (sc-or-lose 'single-reg)
+                              :offset (+ i (tn-offset src)))))
+      (inst fmovs dst src))))
+
+(macrolet ((frob (vop sc format)
+            `(progn
+               (define-vop (,vop)
+                 (:args (x :scs (,sc)
+                           :target y
+                           :load-if (not (location= x y))))
+                 (:results (y :scs (,sc)
+                              :load-if (not (location= x y))))
+                 (:note "float move")
+                 (:generator 0
+                   (unless (location= y x)
+                     ,@(ecase format
+                         (:single `((inst fmovs y x)))
+                         (:double `((move-double-reg y x)))
+                         (:long `((move-long-reg y x)))))))
+               (define-move-vop ,vop :move (,sc) (,sc)))))
+  (frob single-move single-reg :single)
+  (frob double-move double-reg :double)
+  #!+long-float
+  (frob long-move long-reg :long))
+
+
+(define-vop (move-from-float)
+  (:args (x :to :save))
+  (:results (y))
+  (:note "float to pointer coercion")
+  (:temporary (:scs (non-descriptor-reg)) ndescr)
+  (:variant-vars format size type data)
+  (:generator 13
+    (with-fixed-allocation (y ndescr type size))
+    (ecase format
+      (:single
+       (inst stf x y (- (* data n-word-bytes) other-pointer-lowtag)))
+      (:double
+       (inst stdf x y (- (* data n-word-bytes) other-pointer-lowtag)))
+      (:long
+       (store-long-reg x y (- (* data n-word-bytes)
+                             other-pointer-lowtag))))))
+
+(macrolet ((frob (name sc &rest args)
+            `(progn
+               (define-vop (,name move-from-float)
+                 (:args (x :scs (,sc) :to :save))
+                 (:results (y :scs (descriptor-reg)))
+                 (:variant ,@args))
+               (define-move-vop ,name :move (,sc) (descriptor-reg)))))
+  (frob move-from-single single-reg :single
+    single-float-size single-float-widetag single-float-value-slot)
+  (frob move-from-double double-reg :double
+    double-float-size double-float-widetag double-float-value-slot)
+  #!+long-float
+  (frob move-from-long long-reg        :long
+     long-float-size long-float-widetag long-float-value-slot))
+
+(macrolet ((frob (name sc format value)
+            `(progn
+               (define-vop (,name)
+                 (:args (x :scs (descriptor-reg)))
+                 (:results (y :scs (,sc)))
+                 (:note "pointer to float coercion")
+                 (:generator 2
+                   (inst ,(ecase format
+                            (:single 'ldf)
+                            (:double 'lddf))
+                         y x
+                         (- (* ,value n-word-bytes) other-pointer-lowtag))))
+               (define-move-vop ,name :move (descriptor-reg) (,sc)))))
+  (frob move-to-single single-reg :single single-float-value-slot)
+  (frob move-to-double double-reg :double double-float-value-slot))
+
+#!+long-float
+(define-vop (move-to-long)
+  (:args (x :scs (descriptor-reg)))
+  (:results (y :scs (long-reg)))
+  (:note "pointer to float coercion")
+  (:generator 2
+    (load-long-reg y x (- (* long-float-value-slot n-word-bytes)
+                         other-pointer-lowtag))))
+#!+long-float
+(define-move-vop move-to-long :move (descriptor-reg) (long-reg))
+
+(macrolet ((frob (name sc stack-sc format)
+            `(progn
+               (define-vop (,name)
+                 (:args (x :scs (,sc) :target y)
+                        (nfp :scs (any-reg)
+                             :load-if (not (sc-is y ,sc))))
+                 (:results (y))
+                 (:note "float argument move")
+                 (:generator ,(ecase format (:single 1) (:double 2))
+                   (sc-case y
+                     (,sc
+                      (unless (location= x y)
+                        ,@(ecase format
+                            (:single '((inst fmovs y x)))
+                            (:double '((move-double-reg y x))))))
+                     (,stack-sc
+                      (let ((offset (* (tn-offset y) n-word-bytes)))
+                        (inst ,(ecase format
+                                 (:single 'stf)
+                                 (:double 'stdf))
+                              x nfp offset))))))
+               (define-move-vop ,name :move-arg
+                 (,sc descriptor-reg) (,sc)))))
+  (frob move-single-float-arg single-reg single-stack :single)
+  (frob move-double-float-arg double-reg double-stack :double))
+
+#!+long-float
+(define-vop (move-long-float-arg)
+  (:args (x :scs (long-reg) :target y)
+        (nfp :scs (any-reg) :load-if (not (sc-is y long-reg))))
+  (:results (y))
+  (:note "float argument move")
+  (:generator 3
+    (sc-case y
+      (long-reg
+       (unless (location= x y)
+        (move-long-reg y x)))
+      (long-stack
+       (let ((offset (* (tn-offset y) n-word-bytes)))
+        (store-long-reg x nfp offset))))))
+;;;
+#!+long-float
+(define-move-vop move-long-float-arg :move-arg
+  (long-reg descriptor-reg) (long-reg))
+
+\f
+;;;; Complex float move functions
+
+(defun complex-single-reg-real-tn (x)
+  (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
+                 :offset (tn-offset x)))
+(defun complex-single-reg-imag-tn (x)
+  (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
+                 :offset (1+ (tn-offset x))))
+
+(defun complex-double-reg-real-tn (x)
+  (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
+                 :offset (tn-offset x)))
+(defun complex-double-reg-imag-tn (x)
+  (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
+                 :offset (+ (tn-offset x) 2)))
+
+#!+long-float
+(defun complex-long-reg-real-tn (x)
+  (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
+                 :offset (tn-offset x)))
+#!+long-float
+(defun complex-long-reg-imag-tn (x)
+  (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
+                 :offset (+ (tn-offset x) 4)))
+
+
+(define-move-fun (load-complex-single 2) (vop x y)
+  ((complex-single-stack) (complex-single-reg))
+  (let ((nfp (current-nfp-tn vop))
+       (offset (* (tn-offset x) n-word-bytes)))
+    (let ((real-tn (complex-single-reg-real-tn y)))
+      (inst ldf real-tn nfp offset))
+    (let ((imag-tn (complex-single-reg-imag-tn y)))
+      (inst ldf imag-tn nfp (+ offset n-word-bytes)))))
+
+(define-move-fun (store-complex-single 2) (vop x y)
+  ((complex-single-reg) (complex-single-stack))
+  (let ((nfp (current-nfp-tn vop))
+       (offset (* (tn-offset y) n-word-bytes)))
+    (let ((real-tn (complex-single-reg-real-tn x)))
+      (inst stf real-tn nfp offset))
+    (let ((imag-tn (complex-single-reg-imag-tn x)))
+      (inst stf imag-tn nfp (+ offset n-word-bytes)))))
+
+
+(define-move-fun (load-complex-double 4) (vop x y)
+  ((complex-double-stack) (complex-double-reg))
+  (let ((nfp (current-nfp-tn vop))
+       (offset (* (tn-offset x) n-word-bytes)))
+    (let ((real-tn (complex-double-reg-real-tn y)))
+      (inst lddf real-tn nfp offset))
+    (let ((imag-tn (complex-double-reg-imag-tn y)))
+      (inst lddf imag-tn nfp (+ offset (* 2 n-word-bytes))))))
+
+(define-move-fun (store-complex-double 4) (vop x y)
+  ((complex-double-reg) (complex-double-stack))
+  (let ((nfp (current-nfp-tn vop))
+       (offset (* (tn-offset y) n-word-bytes)))
+    (let ((real-tn (complex-double-reg-real-tn x)))
+      (inst stdf real-tn nfp offset))
+    (let ((imag-tn (complex-double-reg-imag-tn x)))
+      (inst stdf imag-tn nfp (+ offset (* 2 n-word-bytes))))))
+
+
+#!+long-float
+(define-move-fun (load-complex-long 5) (vop x y)
+  ((complex-long-stack) (complex-long-reg))
+  (let ((nfp (current-nfp-tn vop))
+       (offset (* (tn-offset x) n-word-bytes)))
+    (let ((real-tn (complex-long-reg-real-tn y)))
+      (load-long-reg real-tn nfp offset))
+    (let ((imag-tn (complex-long-reg-imag-tn y)))
+      (load-long-reg imag-tn nfp (+ offset (* 4 n-word-bytes))))))
+
+#!+long-float
+(define-move-fun (store-complex-long 5) (vop x y)
+  ((complex-long-reg) (complex-long-stack))
+  (let ((nfp (current-nfp-tn vop))
+       (offset (* (tn-offset y) n-word-bytes)))
+    (let ((real-tn (complex-long-reg-real-tn x)))
+      (store-long-reg real-tn nfp offset))
+    (let ((imag-tn (complex-long-reg-imag-tn x)))
+      (store-long-reg imag-tn nfp (+ offset (* 4 n-word-bytes))))))
+
+;;;
+;;; Complex float register to register moves.
+;;;
+(define-vop (complex-single-move)
+  (:args (x :scs (complex-single-reg) :target y
+           :load-if (not (location= x y))))
+  (:results (y :scs (complex-single-reg) :load-if (not (location= x y))))
+  (:note "complex single float move")
+  (:generator 0
+     (unless (location= x y)
+       ;; Note the complex-float-regs are aligned to every second
+       ;; float register so there is not need to worry about overlap.
+       (let ((x-real (complex-single-reg-real-tn x))
+            (y-real (complex-single-reg-real-tn y)))
+        (inst fmovs y-real x-real))
+       (let ((x-imag (complex-single-reg-imag-tn x))
+            (y-imag (complex-single-reg-imag-tn y)))
+        (inst fmovs y-imag x-imag)))))
+;;;
+(define-move-vop complex-single-move :move
+  (complex-single-reg) (complex-single-reg))
+
+(define-vop (complex-double-move)
+  (:args (x :scs (complex-double-reg)
+           :target y :load-if (not (location= x y))))
+  (:results (y :scs (complex-double-reg) :load-if (not (location= x y))))
+  (:note "complex double float move")
+  (:generator 0
+     (unless (location= x y)
+       ;; Note the complex-float-regs are aligned to every second
+       ;; float register so there is not need to worry about overlap.
+       (let ((x-real (complex-double-reg-real-tn x))
+            (y-real (complex-double-reg-real-tn y)))
+        (move-double-reg y-real x-real))
+       (let ((x-imag (complex-double-reg-imag-tn x))
+            (y-imag (complex-double-reg-imag-tn y)))
+        (move-double-reg y-imag x-imag)))))
+;;;
+(define-move-vop complex-double-move :move
+  (complex-double-reg) (complex-double-reg))
+
+#!+long-float
+(define-vop (complex-long-move)
+  (:args (x :scs (complex-long-reg)
+           :target y :load-if (not (location= x y))))
+  (:results (y :scs (complex-long-reg) :load-if (not (location= x y))))
+  (:note "complex long float move")
+  (:generator 0
+     (unless (location= x y)
+       ;; Note the complex-float-regs are aligned to every second
+       ;; float register so there is not need to worry about overlap.
+       (let ((x-real (complex-long-reg-real-tn x))
+            (y-real (complex-long-reg-real-tn y)))
+        (move-long-reg y-real x-real))
+       (let ((x-imag (complex-long-reg-imag-tn x))
+            (y-imag (complex-long-reg-imag-tn y)))
+        (move-long-reg y-imag x-imag)))))
+;;;
+#!+long-float
+(define-move-vop complex-long-move :move
+  (complex-long-reg) (complex-long-reg))
+
+;;;
+;;; Move from a complex float to a descriptor register allocating a
+;;; new complex float object in the process.
+;;;
+(define-vop (move-from-complex-single)
+  (:args (x :scs (complex-single-reg) :to :save))
+  (:results (y :scs (descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) ndescr)
+  (:note "complex single float to pointer coercion")
+  (:generator 13
+     (with-fixed-allocation (y ndescr complex-single-float-widetag
+                              complex-single-float-size))
+     (let ((real-tn (complex-single-reg-real-tn x)))
+       (inst stf real-tn y (- (* complex-single-float-real-slot
+                                n-word-bytes)
+                             other-pointer-lowtag)))
+     (let ((imag-tn (complex-single-reg-imag-tn x)))
+       (inst stf imag-tn y (- (* complex-single-float-imag-slot
+                                n-word-bytes)
+                             other-pointer-lowtag)))))
+;;;
+(define-move-vop move-from-complex-single :move
+  (complex-single-reg) (descriptor-reg))
+
+(define-vop (move-from-complex-double)
+  (:args (x :scs (complex-double-reg) :to :save))
+  (:results (y :scs (descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) ndescr)
+  (:note "complex double float to pointer coercion")
+  (:generator 13
+     (with-fixed-allocation (y ndescr complex-double-float-widetag
+                              complex-double-float-size))
+     (let ((real-tn (complex-double-reg-real-tn x)))
+       (inst stdf real-tn y (- (* complex-double-float-real-slot
+                                 n-word-bytes)
+                              other-pointer-lowtag)))
+     (let ((imag-tn (complex-double-reg-imag-tn x)))
+       (inst stdf imag-tn y (- (* complex-double-float-imag-slot
+                                 n-word-bytes)
+                              other-pointer-lowtag)))))
+;;;
+(define-move-vop move-from-complex-double :move
+  (complex-double-reg) (descriptor-reg))
+
+#!+long-float
+(define-vop (move-from-complex-long)
+  (:args (x :scs (complex-long-reg) :to :save))
+  (:results (y :scs (descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) ndescr)
+  (:note "complex long float to pointer coercion")
+  (:generator 13
+     (with-fixed-allocation (y ndescr complex-long-float-widetag
+                              complex-long-float-size))
+     (let ((real-tn (complex-long-reg-real-tn x)))
+       (store-long-reg real-tn y (- (* complex-long-float-real-slot
+                                      n-word-bytes)
+                                   other-pointer-lowtag)))
+     (let ((imag-tn (complex-long-reg-imag-tn x)))
+       (store-long-reg imag-tn y (- (* complex-long-float-imag-slot
+                                      n-word-bytes)
+                                   other-pointer-lowtag)))))
+;;;
+#!+long-float
+(define-move-vop move-from-complex-long :move
+  (complex-long-reg) (descriptor-reg))
+
+;;;
+;;; Move from a descriptor to a complex float register
+;;;
+(define-vop (move-to-complex-single)
+  (:args (x :scs (descriptor-reg)))
+  (:results (y :scs (complex-single-reg)))
+  (:note "pointer to complex float coercion")
+  (:generator 2
+    (let ((real-tn (complex-single-reg-real-tn y)))
+      (inst ldf real-tn x (- (* complex-single-float-real-slot n-word-bytes)
+                            other-pointer-lowtag)))
+    (let ((imag-tn (complex-single-reg-imag-tn y)))
+      (inst ldf imag-tn x (- (* complex-single-float-imag-slot n-word-bytes)
+                            other-pointer-lowtag)))))
+(define-move-vop move-to-complex-single :move
+  (descriptor-reg) (complex-single-reg))
+
+(define-vop (move-to-complex-double)
+  (:args (x :scs (descriptor-reg)))
+  (:results (y :scs (complex-double-reg)))
+  (:note "pointer to complex float coercion")
+  (:generator 2
+    (let ((real-tn (complex-double-reg-real-tn y)))
+      (inst lddf real-tn x (- (* complex-double-float-real-slot n-word-bytes)
+                             other-pointer-lowtag)))
+    (let ((imag-tn (complex-double-reg-imag-tn y)))
+      (inst lddf imag-tn x (- (* complex-double-float-imag-slot n-word-bytes)
+                             other-pointer-lowtag)))))
+(define-move-vop move-to-complex-double :move
+  (descriptor-reg) (complex-double-reg))
+
+#!+long-float
+(define-vop (move-to-complex-long)
+  (:args (x :scs (descriptor-reg)))
+  (:results (y :scs (complex-long-reg)))
+  (:note "pointer to complex float coercion")
+  (:generator 2
+    (let ((real-tn (complex-long-reg-real-tn y)))
+      (load-long-reg real-tn x (- (* complex-long-float-real-slot n-word-bytes)
+                                 other-pointer-lowtag)))
+    (let ((imag-tn (complex-long-reg-imag-tn y)))
+      (load-long-reg imag-tn x (- (* complex-long-float-imag-slot n-word-bytes)
+                                 other-pointer-lowtag)))))
+#!+long-float
+(define-move-vop move-to-complex-long :move
+  (descriptor-reg) (complex-long-reg))
+
+;;;
+;;; Complex float move-arg vop
+;;;
+(define-vop (move-complex-single-float-arg)
+  (:args (x :scs (complex-single-reg) :target y)
+        (nfp :scs (any-reg) :load-if (not (sc-is y complex-single-reg))))
+  (:results (y))
+  (:note "complex single-float argument move")
+  (:generator 1
+    (sc-case y
+      (complex-single-reg
+       (unless (location= x y)
+        (let ((x-real (complex-single-reg-real-tn x))
+              (y-real (complex-single-reg-real-tn y)))
+          (inst fmovs y-real x-real))
+        (let ((x-imag (complex-single-reg-imag-tn x))
+              (y-imag (complex-single-reg-imag-tn y)))
+          (inst fmovs y-imag x-imag))))
+      (complex-single-stack
+       (let ((offset (* (tn-offset y) n-word-bytes)))
+        (let ((real-tn (complex-single-reg-real-tn x)))
+          (inst stf real-tn nfp offset))
+        (let ((imag-tn (complex-single-reg-imag-tn x)))
+          (inst stf imag-tn nfp (+ offset n-word-bytes))))))))
+(define-move-vop move-complex-single-float-arg :move-arg
+  (complex-single-reg descriptor-reg) (complex-single-reg))
+
+(define-vop (move-complex-double-float-arg)
+  (:args (x :scs (complex-double-reg) :target y)
+        (nfp :scs (any-reg) :load-if (not (sc-is y complex-double-reg))))
+  (:results (y))
+  (:note "complex double-float argument move")
+  (:generator 2
+    (sc-case y
+      (complex-double-reg
+       (unless (location= x y)
+        (let ((x-real (complex-double-reg-real-tn x))
+              (y-real (complex-double-reg-real-tn y)))
+          (move-double-reg y-real x-real))
+        (let ((x-imag (complex-double-reg-imag-tn x))
+              (y-imag (complex-double-reg-imag-tn y)))
+          (move-double-reg y-imag x-imag))))
+      (complex-double-stack
+       (let ((offset (* (tn-offset y) n-word-bytes)))
+        (let ((real-tn (complex-double-reg-real-tn x)))
+          (inst stdf real-tn nfp offset))
+        (let ((imag-tn (complex-double-reg-imag-tn x)))
+          (inst stdf imag-tn nfp (+ offset (* 2 n-word-bytes)))))))))
+(define-move-vop move-complex-double-float-arg :move-arg
+  (complex-double-reg descriptor-reg) (complex-double-reg))
+
+#!+long-float
+(define-vop (move-complex-long-float-arg)
+  (:args (x :scs (complex-long-reg) :target y)
+        (nfp :scs (any-reg) :load-if (not (sc-is y complex-long-reg))))
+  (:results (y))
+  (:note "complex long-float argument move")
+  (:generator 2
+    (sc-case y
+      (complex-long-reg
+       (unless (location= x y)
+        (let ((x-real (complex-long-reg-real-tn x))
+              (y-real (complex-long-reg-real-tn y)))
+          (move-long-reg y-real x-real))
+        (let ((x-imag (complex-long-reg-imag-tn x))
+              (y-imag (complex-long-reg-imag-tn y)))
+          (move-long-reg y-imag x-imag))))
+      (complex-long-stack
+       (let ((offset (* (tn-offset y) n-word-bytes)))
+        (let ((real-tn (complex-long-reg-real-tn x)))
+          (store-long-reg real-tn nfp offset))
+        (let ((imag-tn (complex-long-reg-imag-tn x)))
+          (store-long-reg imag-tn nfp (+ offset (* 4 n-word-bytes)))))))))
+#!+long-float
+(define-move-vop move-complex-long-float-arg :move-arg
+  (complex-long-reg descriptor-reg) (complex-long-reg))
+
+
+(define-move-vop move-arg :move-arg
+  (single-reg double-reg #!+long-float long-reg
+   complex-single-reg complex-double-reg #!+long-float complex-long-reg)
+  (descriptor-reg))
+
+\f
+;;;; Arithmetic VOPs:
+
+(define-vop (float-op)
+  (:args (x) (y))
+  (:results (r))
+  (:policy :fast-safe)
+  (:note "inline float arithmetic")
+  (:vop-var vop)
+  (:save-p :compute-only))
+
+(macrolet ((frob (name sc ptype)
+            `(define-vop (,name float-op)
+               (:args (x :scs (,sc))
+                      (y :scs (,sc)))
+               (:results (r :scs (,sc)))
+               (:arg-types ,ptype ,ptype)
+               (:result-types ,ptype))))
+  (frob single-float-op single-reg single-float)
+  (frob double-float-op double-reg double-float)
+  #!+long-float
+  (frob long-float-op long-reg long-float))
+
+(macrolet ((frob (op sinst sname scost dinst dname dcost)
+            `(progn
+               (define-vop (,sname single-float-op)
+                 (:translate ,op)
+                 (:generator ,scost
+                   (inst ,sinst r x y)))
+               (define-vop (,dname double-float-op)
+                 (:translate ,op)
+                 (:generator ,dcost
+                   (inst ,dinst r x y))))))
+  (frob + fadds +/single-float 2 faddd +/double-float 2)
+  (frob - fsubs -/single-float 2 fsubd -/double-float 2)
+  (frob * fmuls */single-float 4 fmuld */double-float 5)
+  (frob / fdivs //single-float 12 fdivd //double-float 19))
+
+#!+long-float
+(macrolet ((frob (op linst lname lcost)
+            `(define-vop (,lname long-float-op)
+                 (:translate ,op)
+                 (:generator ,lcost
+                   (inst ,linst r x y)))))
+  (frob + faddq +/long-float 2)
+  (frob - fsubq -/long-float 2)
+  (frob * fmulq */long-float 6)
+  (frob / fdivq //long-float 20))
+
+\f
+(macrolet ((frob (name inst translate sc type)
+            `(define-vop (,name)
+               (:args (x :scs (,sc)))
+               (:results (y :scs (,sc)))
+               (:translate ,translate)
+               (:policy :fast-safe)
+               (:arg-types ,type)
+               (:result-types ,type)
+               (:note "inline float arithmetic")
+               (:vop-var vop)
+               (:save-p :compute-only)
+               (:generator 1
+                 (note-this-location vop :internal-error)
+                 (inst ,inst y x)))))
+  (frob abs/single-float fabss abs single-reg single-float)
+  (frob %negate/single-float fnegs %negate single-reg single-float))
+
+(defun negate-double-reg (dst src)
+  #!+:sparc-v9
+  (inst fnegd dst src)
+  #!-:sparc-v9
+  ;; Negate the MS part of the numbers, then copy over the rest
+  ;; of the bits.
+  (inst fnegs dst src)
+  (let ((dst-odd (make-random-tn :kind :normal
+                                :sc (sc-or-lose 'single-reg)
+                                :offset (+ 1 (tn-offset dst))))
+       (src-odd (make-random-tn :kind :normal
+                                :sc (sc-or-lose 'single-reg)
+                                :offset (+ 1 (tn-offset src)))))
+    (inst fmovs dst-odd src-odd)))
+
+(defun abs-double-reg (dst src)
+  #!+:sparc-v9
+  (inst fabsd dst src)
+  #!-:sparc-v9
+  ;; Abs the MS part of the numbers, then copy over the rest
+  ;; of the bits.
+  (inst fabss dst src)
+  (let ((dst-2 (make-random-tn :kind :normal
+                              :sc (sc-or-lose 'single-reg)
+                              :offset (+ 1 (tn-offset dst))))
+       (src-2 (make-random-tn :kind :normal
+                              :sc (sc-or-lose 'single-reg)
+                              :offset (+ 1 (tn-offset src)))))
+    (inst fmovs dst-2 src-2)))
+
+(define-vop (abs/double-float)
+  (:args (x :scs (double-reg)))
+  (:results (y :scs (double-reg)))
+  (:translate abs)
+  (:policy :fast-safe)
+  (:arg-types double-float)
+  (:result-types double-float)
+  (:note "inline float arithmetic")
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:generator 1
+    (note-this-location vop :internal-error)
+    (abs-double-reg y x)))
+
+(define-vop (%negate/double-float)
+  (:args (x :scs (double-reg)))
+  (:results (y :scs (double-reg)))
+  (:translate %negate)
+  (:policy :fast-safe)
+  (:arg-types double-float)
+  (:result-types double-float)
+  (:note "inline float arithmetic")
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:generator 1
+    (note-this-location vop :internal-error)
+    (negate-double-reg y x)))
+
+#!+long-float
+(define-vop (abs/long-float)
+  (:args (x :scs (long-reg)))
+  (:results (y :scs (long-reg)))
+  (:translate abs)
+  (:policy :fast-safe)
+  (:arg-types long-float)
+  (:result-types long-float)
+  (:note "inline float arithmetic")
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:generator 1
+    (note-this-location vop :internal-error)
+    #!+:sparc-v9
+    (inst fabsq y x)
+    #!-:sparc-v9
+    (inst fabss y x)
+    (dotimes (i 3)
+      (let ((y-odd (make-random-tn
+                   :kind :normal
+                   :sc (sc-or-lose 'single-reg)
+                   :offset (+ i 1 (tn-offset y))))
+           (x-odd (make-random-tn
+                   :kind :normal
+                   :sc (sc-or-lose 'single-reg)
+                   :offset (+ i 1 (tn-offset x)))))
+       (inst fmovs y-odd x-odd)))))
+
+#!+long-float
+(define-vop (%negate/long-float)
+  (:args (x :scs (long-reg)))
+  (:results (y :scs (long-reg)))
+  (:translate %negate)
+  (:policy :fast-safe)
+  (:arg-types long-float)
+  (:result-types long-float)
+  (:note "inline float arithmetic")
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:generator 1
+    (note-this-location vop :internal-error)
+    #!+:sparc-v9
+    (inst fnegq y x)
+    #!-:sparc-v9
+    (inst fnegs y x)
+    (dotimes (i 3)
+      (let ((y-odd (make-random-tn
+                   :kind :normal
+                   :sc (sc-or-lose 'single-reg)
+                   :offset (+ i 1 (tn-offset y))))
+           (x-odd (make-random-tn
+                   :kind :normal
+                   :sc (sc-or-lose 'single-reg)
+                   :offset (+ i 1 (tn-offset x)))))
+       (inst fmovs y-odd x-odd)))))
+
+\f
+;;;; Comparison:
+
+(define-vop (float-compare)
+  (:args (x) (y))
+  (:conditional)
+  (:info target not-p)
+  (:variant-vars format yep nope)
+  (:policy :fast-safe)
+  (:note "inline float comparison")
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:generator 3
+    (note-this-location vop :internal-error)
+    (ecase format
+      (:single (inst fcmps x y))
+      (:double (inst fcmpd x y))
+      (:long (inst fcmpq x y)))
+    ;; The SPARC V9 doesn't need an instruction between a
+    ;; floating-point compare and a floating-point branch.
+    #!-:sparc-v9 (inst nop)
+    (inst fb (if not-p nope yep) target)
+    (inst nop)))
+
+(macrolet ((frob (name sc ptype)
+            `(define-vop (,name float-compare)
+               (:args (x :scs (,sc))
+                      (y :scs (,sc)))
+               (:arg-types ,ptype ,ptype))))
+  (frob single-float-compare single-reg single-float)
+  (frob double-float-compare double-reg double-float)
+  #!+long-float
+  (frob long-float-compare long-reg long-float))
+
+(macrolet ((frob (translate yep nope sname dname #!+long-float lname)
+            `(progn
+               (define-vop (,sname single-float-compare)
+                 (:translate ,translate)
+                 (:variant :single ,yep ,nope))
+               (define-vop (,dname double-float-compare)
+                 (:translate ,translate)
+                 (:variant :double ,yep ,nope))
+               #!+long-float
+               (define-vop (,lname long-float-compare)
+                 (:translate ,translate)
+                 (:variant :long ,yep ,nope)))))
+  (frob < :l :ge </single-float </double-float #!+long-float </long-float)
+  (frob > :g :le >/single-float >/double-float #!+long-float >/long-float)
+  (frob = :eq :ne eql/single-float eql/double-float #!+long-float eql/long-float))
+
+#!+long-float
+(deftransform eql ((x y) (long-float long-float))
+  '(and (= (long-float-low-bits x) (long-float-low-bits y))
+       (= (long-float-mid-bits x) (long-float-mid-bits y))
+       (= (long-float-high-bits x) (long-float-high-bits y))
+       (= (long-float-exp-bits x) (long-float-exp-bits y))))
+
+\f
+;;;; Conversion:
+
+(macrolet ((frob (name translate inst to-sc to-type)
+            `(define-vop (,name)
+               (:args (x :scs (signed-reg) :target stack-temp
+                         :load-if (not (sc-is x signed-stack))))
+               (:temporary (:scs (single-stack) :from :argument) stack-temp)
+               (:temporary (:scs (single-reg) :to :result :target y) temp)
+               (:results (y :scs (,to-sc)))
+               (:arg-types signed-num)
+               (:result-types ,to-type)
+               (:policy :fast-safe)
+               (:note "inline float coercion")
+               (:translate ,translate)
+               (:vop-var vop)
+               (:save-p :compute-only)
+               (:generator 5
+                 (let ((stack-tn
+                        (sc-case x
+                          (signed-reg
+                           (inst st x
+                                 (current-nfp-tn vop)
+                                 (* (tn-offset temp) n-word-bytes))
+                           stack-temp)
+                          (signed-stack
+                           x))))
+                   (inst ldf temp
+                         (current-nfp-tn vop)
+                         (* (tn-offset stack-tn) n-word-bytes))
+                   (note-this-location vop :internal-error)
+                   (inst ,inst y temp))))))
+  (frob %single-float/signed %single-float fitos single-reg single-float)
+  (frob %double-float/signed %double-float fitod double-reg double-float)
+  #!+long-float
+  (frob %long-float/signed %long-float fitoq long-reg long-float))
+
+(macrolet ((frob (name translate inst from-sc from-type to-sc to-type)
+            `(define-vop (,name)
+               (:args (x :scs (,from-sc)))
+               (:results (y :scs (,to-sc)))
+               (:arg-types ,from-type)
+               (:result-types ,to-type)
+               (:policy :fast-safe)
+               (:note "inline float coercion")
+               (:translate ,translate)
+               (:vop-var vop)
+               (:save-p :compute-only)
+               (:generator 2
+                 (note-this-location vop :internal-error)
+                 (inst ,inst y x)))))
+  (frob %single-float/double-float %single-float fdtos
+    double-reg double-float single-reg single-float)
+  #!+long-float
+  (frob %single-float/long-float %single-float fqtos
+    long-reg long-float single-reg single-float)
+  (frob %double-float/single-float %double-float fstod
+    single-reg single-float double-reg double-float)
+  #!+long-float
+  (frob %double-float/long-float %double-float fqtod
+    long-reg long-float double-reg double-float)
+  #!+long-float
+  (frob %long-float/single-float %long-float fstoq
+    single-reg single-float long-reg long-float)
+  #!+long-float
+  (frob %long-float/double-float %long-float fdtoq
+    double-reg double-float long-reg long-float))
+
+(macrolet ((frob (trans from-sc from-type inst)
+            `(define-vop (,(symbolicate trans "/" from-type))
+               (:args (x :scs (,from-sc) :target temp))
+               (:temporary (:from (:argument 0) :sc single-reg) temp)
+               (:temporary (:scs (signed-stack)) stack-temp)
+               (:results (y :scs (signed-reg)
+                            :load-if (not (sc-is y signed-stack))))
+               (:arg-types ,from-type)
+               (:result-types signed-num)
+               (:translate ,trans)
+               (:policy :fast-safe)
+               (:note "inline float truncate")
+               (:vop-var vop)
+               (:save-p :compute-only)
+               (:generator 5
+                 (note-this-location vop :internal-error)
+                 (inst ,inst temp x)
+                 (sc-case y
+                   (signed-stack
+                    (inst stf temp (current-nfp-tn vop)
+                          (* (tn-offset y) n-word-bytes)))
+                   (signed-reg
+                    (inst stf temp (current-nfp-tn vop)
+                          (* (tn-offset stack-temp) n-word-bytes))
+                    (inst ld y (current-nfp-tn vop)
+                          (* (tn-offset stack-temp) n-word-bytes))))))))
+  (frob %unary-truncate single-reg single-float fstoi)
+  (frob %unary-truncate double-reg double-float fdtoi)
+  #!+long-float
+  (frob %unary-truncate long-reg long-float fqtoi)
+  ;; KLUDGE -- these two forms were protected by #-sun4.
+  ;; (frob %unary-round single-reg single-float fstoir)
+  ;; (frob %unary-round double-reg double-float fdtoir)
+)
+
+(deftransform %unary-round ((x) (float) (signed-byte 32))
+  '(let* ((trunc (truly-the (signed-byte 32) (%unary-truncate x)))
+         (extra (- x trunc))
+         (absx (abs extra))
+         (one-half (float 1/2 x)))
+     (if (if (oddp trunc)
+            (>= absx one-half)
+            (> absx one-half))
+        (truly-the (signed-byte 32) (%unary-truncate (+ x extra)))
+        trunc)))
+
+(define-vop (make-single-float)
+  (:args (bits :scs (signed-reg) :target res
+              :load-if (not (sc-is bits signed-stack))))
+  (:results (res :scs (single-reg)
+                :load-if (not (sc-is res single-stack))))
+  (:temporary (:scs (signed-reg) :from (:argument 0) :to (:result 0)) temp)
+  (:temporary (:scs (signed-stack)) stack-temp)
+  (:arg-types signed-num)
+  (:result-types single-float)
+  (:translate make-single-float)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 4
+    (sc-case bits
+      (signed-reg
+       (sc-case res
+        (single-reg
+         (inst st bits (current-nfp-tn vop)
+               (* (tn-offset stack-temp) n-word-bytes))
+         (inst ldf res (current-nfp-tn vop)
+               (* (tn-offset stack-temp) n-word-bytes)))
+        (single-stack
+         (inst st bits (current-nfp-tn vop)
+               (* (tn-offset res) n-word-bytes)))))
+      (signed-stack
+       (sc-case res
+        (single-reg
+         (inst ldf res (current-nfp-tn vop)
+               (* (tn-offset bits) n-word-bytes)))
+        (single-stack
+         (unless (location= bits res)
+           (inst ld temp (current-nfp-tn vop)
+                 (* (tn-offset bits) n-word-bytes))
+           (inst st temp (current-nfp-tn vop)
+                 (* (tn-offset res) n-word-bytes)))))))))
+
+(define-vop (make-double-float)
+  (:args (hi-bits :scs (signed-reg))
+        (lo-bits :scs (unsigned-reg)))
+  (:results (res :scs (double-reg)
+                :load-if (not (sc-is res double-stack))))
+  (:temporary (:scs (double-stack)) temp)
+  (:arg-types signed-num unsigned-num)
+  (:result-types double-float)
+  (:translate make-double-float)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 2
+    (let ((stack-tn (sc-case res
+                     (double-stack res)
+                     (double-reg temp))))
+      (inst st hi-bits (current-nfp-tn vop)
+           (* (tn-offset stack-tn) n-word-bytes))
+      (inst st lo-bits (current-nfp-tn vop)
+           (* (1+ (tn-offset stack-tn)) n-word-bytes)))
+    (when (sc-is res double-reg)
+      (inst lddf res (current-nfp-tn vop)
+           (* (tn-offset temp) n-word-bytes)))))
+
+#!+long-float
+(define-vop (make-long-float)
+    (:args (hi-bits :scs (signed-reg))
+          (lo1-bits :scs (unsigned-reg))
+          (lo2-bits :scs (unsigned-reg))
+          (lo3-bits :scs (unsigned-reg)))
+  (:results (res :scs (long-reg)
+                :load-if (not (sc-is res long-stack))))
+  (:temporary (:scs (long-stack)) temp)
+  (:arg-types signed-num unsigned-num unsigned-num unsigned-num)
+  (:result-types long-float)
+  (:translate make-long-float)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 2
+    (let ((stack-tn (sc-case res
+                     (long-stack res)
+                     (long-reg temp))))
+      (inst st hi-bits (current-nfp-tn vop)
+           (* (tn-offset stack-tn) n-word-bytes))
+      (inst st lo1-bits (current-nfp-tn vop)
+           (* (1+ (tn-offset stack-tn)) n-word-bytes))
+      (inst st lo2-bits (current-nfp-tn vop)
+           (* (+ 2 (tn-offset stack-tn)) n-word-bytes))
+      (inst st lo3-bits (current-nfp-tn vop)
+           (* (+ 3 (tn-offset stack-tn)) n-word-bytes)))
+    (when (sc-is res long-reg)
+      (load-long-reg res (current-nfp-tn vop)
+                    (* (tn-offset temp) n-word-bytes)))))
+
+(define-vop (single-float-bits)
+  (:args (float :scs (single-reg descriptor-reg)
+               :load-if (not (sc-is float single-stack))))
+  (:results (bits :scs (signed-reg)
+                 :load-if (or (sc-is float descriptor-reg single-stack)
+                              (not (sc-is bits signed-stack)))))
+  (:temporary (:scs (signed-stack)) stack-temp)
+  (:arg-types single-float)
+  (:result-types signed-num)
+  (:translate single-float-bits)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 4
+    (sc-case bits
+      (signed-reg
+       (sc-case float
+        (single-reg
+         (inst stf float (current-nfp-tn vop)
+               (* (tn-offset stack-temp) n-word-bytes))
+         (inst ld bits (current-nfp-tn vop)
+               (* (tn-offset stack-temp) n-word-bytes)))
+        (single-stack
+         (inst ld bits (current-nfp-tn vop)
+               (* (tn-offset float) n-word-bytes)))
+        (descriptor-reg
+         (loadw bits float single-float-value-slot
+                other-pointer-lowtag))))
+      (signed-stack
+       (sc-case float
+        (single-reg
+         (inst stf float (current-nfp-tn vop)
+               (* (tn-offset bits) n-word-bytes))))))))
+
+(define-vop (double-float-high-bits)
+  (:args (float :scs (double-reg descriptor-reg)
+               :load-if (not (sc-is float double-stack))))
+  (:results (hi-bits :scs (signed-reg)))
+  (:temporary (:scs (double-stack)) stack-temp)
+  (:arg-types double-float)
+  (:result-types signed-num)
+  (:translate double-float-high-bits)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 5
+    (sc-case float
+      (double-reg
+       (inst stdf float (current-nfp-tn vop)
+            (* (tn-offset stack-temp) n-word-bytes))
+       (inst ld hi-bits (current-nfp-tn vop)
+            (* (tn-offset stack-temp) n-word-bytes)))
+      (double-stack
+       (inst ld hi-bits (current-nfp-tn vop)
+            (* (tn-offset float) n-word-bytes)))
+      (descriptor-reg
+       (loadw hi-bits float double-float-value-slot
+             other-pointer-lowtag)))))
+
+(define-vop (double-float-low-bits)
+  (:args (float :scs (double-reg descriptor-reg)
+               :load-if (not (sc-is float double-stack))))
+  (:results (lo-bits :scs (unsigned-reg)))
+  (:temporary (:scs (double-stack)) stack-temp)
+  (:arg-types double-float)
+  (:result-types unsigned-num)
+  (:translate double-float-low-bits)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 5
+    (sc-case float
+      (double-reg
+       (inst stdf float (current-nfp-tn vop)
+            (* (tn-offset stack-temp) n-word-bytes))
+       (inst ld lo-bits (current-nfp-tn vop)
+            (* (1+ (tn-offset stack-temp)) n-word-bytes)))
+      (double-stack
+       (inst ld lo-bits (current-nfp-tn vop)
+            (* (1+ (tn-offset float)) n-word-bytes)))
+      (descriptor-reg
+       (loadw lo-bits float (1+ double-float-value-slot)
+             other-pointer-lowtag)))))
+
+#!+long-float
+(define-vop (long-float-exp-bits)
+  (:args (float :scs (long-reg descriptor-reg)
+               :load-if (not (sc-is float long-stack))))
+  (:results (exp-bits :scs (signed-reg)))
+  (:temporary (:scs (double-stack)) stack-temp)
+  (:arg-types long-float)
+  (:result-types signed-num)
+  (:translate long-float-exp-bits)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 5
+    (sc-case float
+      (long-reg
+       (let ((float (make-random-tn :kind :normal
+                                   :sc (sc-or-lose 'double-reg)
+                                   :offset (tn-offset float))))
+        (inst stdf float (current-nfp-tn vop)
+              (* (tn-offset stack-temp) n-word-bytes)))
+       (inst ld exp-bits (current-nfp-tn vop)
+            (* (tn-offset stack-temp) n-word-bytes)))
+      (long-stack
+       (inst ld exp-bits (current-nfp-tn vop)
+            (* (tn-offset float) n-word-bytes)))
+      (descriptor-reg
+       (loadw exp-bits float long-float-value-slot
+             other-pointer-lowtag)))))
+
+#!+long-float
+(define-vop (long-float-high-bits)
+  (:args (float :scs (long-reg descriptor-reg)
+               :load-if (not (sc-is float long-stack))))
+  (:results (high-bits :scs (unsigned-reg)))
+  (:temporary (:scs (double-stack)) stack-temp)
+  (:arg-types long-float)
+  (:result-types unsigned-num)
+  (:translate long-float-high-bits)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 5
+    (sc-case float
+      (long-reg
+       (let ((float (make-random-tn :kind :normal
+                                   :sc (sc-or-lose 'double-reg)
+                                   :offset (tn-offset float))))
+        (inst stdf float (current-nfp-tn vop)
+              (* (tn-offset stack-temp) n-word-bytes)))
+       (inst ld high-bits (current-nfp-tn vop)
+            (* (1+ (tn-offset stack-temp)) n-word-bytes)))
+      (long-stack
+       (inst ld high-bits (current-nfp-tn vop)
+            (* (1+ (tn-offset float)) n-word-bytes)))
+      (descriptor-reg
+       (loadw high-bits float (1+ long-float-value-slot)
+             other-pointer-lowtag)))))
+
+#!+long-float
+(define-vop (long-float-mid-bits)
+  (:args (float :scs (long-reg descriptor-reg)
+               :load-if (not (sc-is float long-stack))))
+  (:results (mid-bits :scs (unsigned-reg)))
+  (:temporary (:scs (double-stack)) stack-temp)
+  (:arg-types long-float)
+  (:result-types unsigned-num)
+  (:translate long-float-mid-bits)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 5
+    (sc-case float
+      (long-reg
+       (let ((float (make-random-tn :kind :normal
+                                   :sc (sc-or-lose 'double-reg)
+                                   :offset (+ 2 (tn-offset float)))))
+        (inst stdf float (current-nfp-tn vop)
+              (* (tn-offset stack-temp) n-word-bytes)))
+       (inst ld mid-bits (current-nfp-tn vop)
+            (* (tn-offset stack-temp) n-word-bytes)))
+      (long-stack
+       (inst ld mid-bits (current-nfp-tn vop)
+            (* (+ 2 (tn-offset float)) n-word-bytes)))
+      (descriptor-reg
+       (loadw mid-bits float (+ 2 long-float-value-slot)
+             other-pointer-lowtag)))))
+
+#!+long-float
+(define-vop (long-float-low-bits)
+  (:args (float :scs (long-reg descriptor-reg)
+               :load-if (not (sc-is float long-stack))))
+  (:results (lo-bits :scs (unsigned-reg)))
+  (:temporary (:scs (double-stack)) stack-temp)
+  (:arg-types long-float)
+  (:result-types unsigned-num)
+  (:translate long-float-low-bits)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 5
+    (sc-case float
+      (long-reg
+       (let ((float (make-random-tn :kind :normal
+                                   :sc (sc-or-lose 'double-reg)
+                                   :offset (+ 2 (tn-offset float)))))
+        (inst stdf float (current-nfp-tn vop)
+              (* (tn-offset stack-temp) n-word-bytes)))
+       (inst ld lo-bits (current-nfp-tn vop)
+            (* (1+ (tn-offset stack-temp)) n-word-bytes)))
+      (long-stack
+       (inst ld lo-bits (current-nfp-tn vop)
+            (* (+ 3 (tn-offset float)) n-word-bytes)))
+      (descriptor-reg
+       (loadw lo-bits float (+ 3 long-float-value-slot)
+             other-pointer-lowtag)))))
+
+\f
+;;;; Float mode hackery:
+
+(sb!xc:deftype float-modes () '(unsigned-byte 32))
+(defknown floating-point-modes () float-modes (flushable))
+(defknown ((setf floating-point-modes)) (float-modes)
+  float-modes)
+
+(define-vop (floating-point-modes)
+  (:results (res :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:translate floating-point-modes)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:temporary (:sc unsigned-stack) temp)
+  (:generator 3
+    (let ((nfp (current-nfp-tn vop)))
+      (inst stfsr nfp (* n-word-bytes (tn-offset temp)))
+      (loadw res nfp (tn-offset temp))
+      (inst nop))))
+
+#+nil
+(define-vop (floating-point-modes)
+  (:results (res :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:translate floating-point-modes)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:temporary (:sc double-stack) temp)
+  (:generator 3
+    (let* ((nfp (current-nfp-tn vop))
+          (offset (* 4 (tn-offset temp))))
+      (inst stxfsr nfp offset)
+      ;; The desired FP mode data is in the least significant 32
+      ;; bits, which is stored at the next higher word in memory.
+      (loadw res nfp (+ offset 4))
+      ;; Is this nop needed? (toy@rtp.ericsson.se)
+      (inst nop))))
+
+(define-vop (set-floating-point-modes)
+  (:args (new :scs (unsigned-reg) :target res))
+  (:results (res :scs (unsigned-reg)))
+  (:arg-types unsigned-num)
+  (:result-types unsigned-num)
+  (:translate (setf floating-point-modes))
+  (:policy :fast-safe)
+  (:temporary (:sc unsigned-stack) temp)
+  (:vop-var vop)
+  (:generator 3
+    (let ((nfp (current-nfp-tn vop)))
+      (storew new nfp (tn-offset temp))
+      (inst ldfsr nfp (* n-word-bytes (tn-offset temp)))
+      (move res new))))
+
+#+nil
+(define-vop (set-floating-point-modes)
+  (:args (new :scs (unsigned-reg) :target res))
+  (:results (res :scs (unsigned-reg)))
+  (:arg-types unsigned-num)
+  (:result-types unsigned-num)
+  (:translate (setf floating-point-modes))
+  (:policy :fast-safe)
+  (:temporary (:sc double-stack) temp)
+  (:temporary (:sc unsigned-reg) my-fsr)
+  (:vop-var vop)
+  (:generator 3
+    (let ((nfp (current-nfp-tn vop))
+         (offset (* n-word-bytes (tn-offset temp))))
+      (pseudo-atomic ()
+        ;; Get the current FSR, so we can get the new %fcc's
+        (inst stxfsr nfp offset)
+       (inst ldx my-fsr nfp offset)
+       ;; Carefully merge in the new mode bits with the rest of the
+       ;; FSR.  This is only needed if we care about preserving the
+       ;; high 32 bits of the FSR, which contain the additional
+       ;; %fcc's on the sparc V9.  If not, we don't need this, but we
+       ;; do need to make sure that the unused bits are written as
+       ;; zeroes, according the the V9 architecture manual.
+       (inst sra new 0)
+       (inst srlx my-fsr 32)
+       (inst sllx my-fsr 32)
+       (inst or my-fsr new)
+       ;; Save it back and load it into the fsr register
+       (inst stx my-fsr nfp offset)
+       (inst ldxfsr nfp offset)
+       (move res new)))))
+
+#+nil
+(define-vop (set-floating-point-modes)
+  (:args (new :scs (unsigned-reg) :target res))
+  (:results (res :scs (unsigned-reg)))
+  (:arg-types unsigned-num)
+  (:result-types unsigned-num)
+  (:translate (setf floating-point-modes))
+  (:policy :fast-safe)
+  (:temporary (:sc double-stack) temp)
+  (:temporary (:sc unsigned-reg) my-fsr)
+  (:vop-var vop)
+  (:generator 3
+    (let ((nfp (current-nfp-tn vop))
+         (offset (* n-word-bytes (tn-offset temp))))
+      (inst stx new nfp offset)
+      (inst ldxfsr nfp offset)
+      (move res new))))
+
+\f
+;;;; Special functions.
+
+#!-long-float
+(define-vop (fsqrt)
+  (:args (x :scs (double-reg)))
+  (:results (y :scs (double-reg)))
+  (:translate %sqrt)
+  (:policy :fast-safe)
+  (:guard #!+(or :sparc-v7 :sparc-v8 :sparc-v9) t
+         #!-(or :sparc-v7 :sparc-v8 :sparc-v9) nil)
+  (:arg-types double-float)
+  (:result-types double-float)
+  (:note "inline float arithmetic")
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:generator 1
+    (note-this-location vop :internal-error)
+    (inst fsqrtd y x)))
+
+#!+long-float
+(define-vop (fsqrt-long)
+  (:args (x :scs (long-reg)))
+  (:results (y :scs (long-reg)))
+  (:translate %sqrt)
+  (:policy :fast-safe)
+  (:arg-types long-float)
+  (:result-types long-float)
+  (:note "inline float arithmetic")
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:generator 1
+    (note-this-location vop :internal-error)
+    (inst fsqrtq y x)))
+
+\f
+;;;; Complex float VOPs
+
+(define-vop (make-complex-single-float)
+  (:translate complex)
+  (:args (real :scs (single-reg) :target r
+              :load-if (not (location= real r)))
+        (imag :scs (single-reg) :to :save))
+  (:arg-types single-float single-float)
+  (:results (r :scs (complex-single-reg) :from (:argument 0)
+              :load-if (not (sc-is r complex-single-stack))))
+  (:result-types complex-single-float)
+  (:note "inline complex single-float creation")
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 5
+    (sc-case r
+      (complex-single-reg
+       (let ((r-real (complex-single-reg-real-tn r)))
+        (unless (location= real r-real)
+          (inst fmovs r-real real)))
+       (let ((r-imag (complex-single-reg-imag-tn r)))
+        (unless (location= imag r-imag)
+          (inst fmovs r-imag imag))))
+      (complex-single-stack
+       (let ((nfp (current-nfp-tn vop))
+            (offset (* (tn-offset r) n-word-bytes)))
+        (unless (location= real r)
+          (inst stf real nfp offset))
+        (inst stf imag nfp (+ offset n-word-bytes)))))))
+
+(define-vop (make-complex-double-float)
+  (:translate complex)
+  (:args (real :scs (double-reg) :target r
+              :load-if (not (location= real r)))
+        (imag :scs (double-reg) :to :save))
+  (:arg-types double-float double-float)
+  (:results (r :scs (complex-double-reg) :from (:argument 0)
+              :load-if (not (sc-is r complex-double-stack))))
+  (:result-types complex-double-float)
+  (:note "inline complex double-float creation")
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 5
+    (sc-case r
+      (complex-double-reg
+       (let ((r-real (complex-double-reg-real-tn r)))
+        (unless (location= real r-real)
+          (move-double-reg r-real real)))
+       (let ((r-imag (complex-double-reg-imag-tn r)))
+        (unless (location= imag r-imag)
+          (move-double-reg r-imag imag))))
+      (complex-double-stack
+       (let ((nfp (current-nfp-tn vop))
+            (offset (* (tn-offset r) n-word-bytes)))
+        (unless (location= real r)
+          (inst stdf real nfp offset))
+        (inst stdf imag nfp (+ offset (* 2 n-word-bytes))))))))
+
+#!+long-float
+(define-vop (make-complex-long-float)
+  (:translate complex)
+  (:args (real :scs (long-reg) :target r
+              :load-if (not (location= real r)))
+        (imag :scs (long-reg) :to :save))
+  (:arg-types long-float long-float)
+  (:results (r :scs (complex-long-reg) :from (:argument 0)
+              :load-if (not (sc-is r complex-long-stack))))
+  (:result-types complex-long-float)
+  (:note "inline complex long-float creation")
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 5
+    (sc-case r
+      (complex-long-reg
+       (let ((r-real (complex-long-reg-real-tn r)))
+        (unless (location= real r-real)
+          (move-long-reg r-real real)))
+       (let ((r-imag (complex-long-reg-imag-tn r)))
+        (unless (location= imag r-imag)
+          (move-long-reg r-imag imag))))
+      (complex-long-stack
+       (let ((nfp (current-nfp-tn vop))
+            (offset (* (tn-offset r) n-word-bytes)))
+        (unless (location= real r)
+          (store-long-reg real nfp offset))
+        (store-long-reg imag nfp (+ offset (* 4 n-word-bytes))))))))
+
+(define-vop (complex-single-float-value)
+  (:args (x :scs (complex-single-reg) :target r
+           :load-if (not (sc-is x complex-single-stack))))
+  (:arg-types complex-single-float)
+  (:results (r :scs (single-reg)))
+  (:result-types single-float)
+  (:variant-vars slot)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 3
+    (sc-case x
+      (complex-single-reg
+       (let ((value-tn (ecase slot
+                        (:real (complex-single-reg-real-tn x))
+                        (:imag (complex-single-reg-imag-tn x)))))
+        (unless (location= value-tn r)
+          (inst fmovs r value-tn))))
+      (complex-single-stack
+       (inst ldf r (current-nfp-tn vop) (* (+ (ecase slot (:real 0) (:imag 1))
+                                             (tn-offset x))
+                                          n-word-bytes))))))
+
+(define-vop (realpart/complex-single-float complex-single-float-value)
+  (:translate realpart)
+  (:note "complex single float realpart")
+  (:variant :real))
+
+(define-vop (imagpart/complex-single-float complex-single-float-value)
+  (:translate imagpart)
+  (:note "complex single float imagpart")
+  (:variant :imag))
+
+(define-vop (complex-double-float-value)
+  (:args (x :scs (complex-double-reg) :target r
+           :load-if (not (sc-is x complex-double-stack))))
+  (:arg-types complex-double-float)
+  (:results (r :scs (double-reg)))
+  (:result-types double-float)
+  (:variant-vars slot)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 3
+    (sc-case x
+      (complex-double-reg
+       (let ((value-tn (ecase slot
+                        (:real (complex-double-reg-real-tn x))
+                        (:imag (complex-double-reg-imag-tn x)))))
+        (unless (location= value-tn r)
+          (move-double-reg r value-tn))))
+      (complex-double-stack
+       (inst lddf r (current-nfp-tn vop) (* (+ (ecase slot (:real 0) (:imag 2))
+                                              (tn-offset x))
+                                           n-word-bytes))))))
+
+(define-vop (realpart/complex-double-float complex-double-float-value)
+  (:translate realpart)
+  (:note "complex double float realpart")
+  (:variant :real))
+
+(define-vop (imagpart/complex-double-float complex-double-float-value)
+  (:translate imagpart)
+  (:note "complex double float imagpart")
+  (:variant :imag))
+
+#!+long-float
+(define-vop (complex-long-float-value)
+  (:args (x :scs (complex-long-reg) :target r
+           :load-if (not (sc-is x complex-long-stack))))
+  (:arg-types complex-long-float)
+  (:results (r :scs (long-reg)))
+  (:result-types long-float)
+  (:variant-vars slot)
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:generator 4
+    (sc-case x
+      (complex-long-reg
+       (let ((value-tn (ecase slot
+                        (:real (complex-long-reg-real-tn x))
+                        (:imag (complex-long-reg-imag-tn x)))))
+        (unless (location= value-tn r)
+          (move-long-reg r value-tn))))
+      (complex-long-stack
+       (load-long-reg r (current-nfp-tn vop)
+                     (* (+ (ecase slot (:real 0) (:imag 4)) (tn-offset x))
+                        n-word-bytes))))))
+
+#!+long-float
+(define-vop (realpart/complex-long-float complex-long-float-value)
+  (:translate realpart)
+  (:note "complex long float realpart")
+  (:variant :real))
+
+#!+long-float
+(define-vop (imagpart/complex-long-float complex-long-float-value)
+  (:translate imagpart)
+  (:note "complex long float imagpart")
+  (:variant :imag))
+
+\f
+
+;;;; Complex float arithmetic
+
+#!+complex-fp-vops
+(progn
+
+;; Negate a complex
+(macrolet
+    ((frob (float-type fneg cost)
+       (let* ((vop-name (symbolicate "%NEGATE/COMPLEX-" float-type))
+             (c-type (symbolicate "COMPLEX-" float-type "-FLOAT"))
+             (complex-reg (symbolicate "COMPLEX-" float-type "-REG"))
+             (real-tn (symbolicate "COMPLEX-" float-type "-REG-REAL-TN"))
+             (imag-tn (symbolicate "COMPLEX-" float-type "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+           (:args (x :scs (,complex-reg)))
+           (:arg-types ,c-type)
+           (:results (r :scs (,complex-reg)))
+           (:result-types ,c-type)
+           (:policy :fast-safe)
+           (:note "inline complex float arithmetic")
+           (:translate %negate)
+           (:generator ,cost
+             (let ((xr (,real-tn x))
+                   (xi (,imag-tn x))
+                   (rr (,real-tn r))
+                   (ri (,imag-tn r)))
+               (,@fneg rr xr)
+               (,@fneg ri xi)))))))
+  (frob single (inst fnegs) 4)
+  (frob double (negate-double-reg) 4))
+
+;; Add and subtract for two complex arguments
+(macrolet
+    ((frob (op inst float-type cost)
+       (let* ((vop-name (symbolicate (symbol-name op) "/COMPLEX-" float-type "-FLOAT"))
+             (c-type (symbolicate "COMPLEX-" float-type "-FLOAT"))
+             (complex-reg (symbolicate "COMPLEX-" float-type "-REG"))
+             (real-part (symbolicate "COMPLEX-" float-type "-REG-REAL-TN"))
+             (imag-part (symbolicate "COMPLEX-" float-type "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+          (:args (x :scs (,complex-reg)) (y :scs (,complex-reg)))
+          (:results (r :scs (,complex-reg)))
+          (:arg-types ,c-type ,c-type)
+          (:result-types ,c-type)
+          (:policy :fast-safe)
+          (:note "inline complex float arithmetic")
+          (:translate ,op)
+          (:generator ,cost
+           (let ((xr (,real-part x))
+                 (xi (,imag-part x))
+                 (yr (,real-part y))
+                 (yi (,imag-part y))
+                 (rr (,real-part r))
+                 (ri (,imag-part r)))
+             (inst ,inst rr xr yr)
+             (inst ,inst ri xi yi)))))))
+  (frob + fadds single 4)
+  (frob + faddd double 4)
+  (frob - fsubs single 4)
+  (frob - fsubd double 4))
+
+;; Add and subtract a complex and a float
+
+(macrolet
+    ((frob (size op fop fmov cost)
+       (let ((vop-name (symbolicate "COMPLEX-" size "-FLOAT-"
+                                   op
+                                   "-" size "-FLOAT"))
+            (complex-reg (symbolicate "COMPLEX-" size "-REG"))
+            (real-reg (symbolicate size "-REG"))
+            (c-type (symbolicate "COMPLEX-" size "-FLOAT"))
+            (r-type (symbolicate size "-FLOAT"))
+            (real-part (symbolicate "COMPLEX-" size "-REG-REAL-TN"))
+            (imag-part (symbolicate "COMPLEX-" size "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+             (:args (x :scs (,complex-reg))
+                    (y :scs (,real-reg)))
+           (:results (r :scs (,complex-reg)))
+           (:arg-types ,c-type ,r-type)
+           (:result-types ,c-type)
+           (:policy :fast-safe)
+           (:note "inline complex float/float arithmetic")
+           (:translate ,op)
+           (:generator ,cost
+             (let ((xr (,real-part x))
+                   (xi (,imag-part x))
+                   (rr (,real-part r))
+                   (ri (,imag-part r)))
+               (inst ,fop rr xr y)
+               (unless (location= ri xi)
+                 (,@fmov ri xi))))))))
+  
+  (frob single + fadds (inst fmovs) 2)
+  (frob single - fsubs (inst fmovs) 2)
+  (frob double + faddd (move-double-reg) 4)
+  (frob double - fsubd (move-double-reg) 4))
+
+;; Add a float and a complex
+(macrolet
+    ((frob (size fop fmov cost)
+       (let ((vop-name
+             (symbolicate size "-FLOAT-+-COMPLEX-" size "-FLOAT"))
+            (complex-reg (symbolicate "COMPLEX-" size "-REG"))
+            (real-reg (symbolicate size "-REG"))
+            (c-type (symbolicate "COMPLEX-" size "-FLOAT"))
+            (r-type (symbolicate size "-FLOAT"))
+            (real-part (symbolicate "COMPLEX-" size "-REG-REAL-TN"))
+            (imag-part (symbolicate "COMPLEX-" size "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+             (:args (y :scs (,real-reg))
+                    (x :scs (,complex-reg)))
+           (:results (r :scs (,complex-reg)))
+           (:arg-types ,r-type ,c-type)
+           (:result-types ,c-type)
+           (:policy :fast-safe)
+           (:note "inline complex float/float arithmetic")
+           (:translate +)
+           (:generator ,cost
+             (let ((xr (,real-part x))
+                   (xi (,imag-part x))
+                   (rr (,real-part r))
+                   (ri (,imag-part r)))
+               (inst ,fop rr xr y)
+               (unless (location= ri xi)
+                 (,@fmov ri xi))))))))
+  (frob single fadds (inst fmovs) 1)
+  (frob double faddd (move-double-reg) 2))
+
+;; Subtract a complex from a float
+
+(macrolet
+    ((frob (size fop fneg cost)
+       (let ((vop-name (symbolicate size "-FLOAT---COMPLEX-" size "-FLOAT"))
+            (complex-reg (symbolicate "COMPLEX-" size "-REG"))
+            (real-reg (symbolicate size "-REG"))
+            (c-type (symbolicate "COMPLEX-" size "-FLOAT"))
+            (r-type (symbolicate size "-FLOAT"))
+            (real-part (symbolicate "COMPLEX-" size "-REG-REAL-TN"))
+            (imag-part (symbolicate "COMPLEX-" size "-REG-IMAG-TN")))
+        `(define-vop (single-float---complex-single-float)
+             (:args (x :scs (,real-reg)) (y :scs (,complex-reg)))
+           (:results (r :scs (,complex-reg)))
+           (:arg-types ,r-type ,c-type)
+           (:result-types ,c-type)
+           (:policy :fast-safe)
+           (:note "inline complex float/float arithmetic")
+           (:translate -)
+           (:generator ,cost
+              (let ((yr (,real-part y))
+                    (yi (,imag-part y))
+                    (rr (,real-part r))
+                    (ri (,imag-part r)))
+                (inst ,fop rr x yr)
+                (,@fneg ri yi))))
+       ))
+
+  (frob single fsubs (inst fnegs) 2)
+  (frob double fsubd (negate-double-reg) 2)))
+
+;; Multiply two complex numbers
+
+#+nil
+(macrolet
+    ((frob (size fmul fadd fsub cost)
+       (let ((vop-name (symbolicate "*/COMPLEX-" size "-FLOAT"))
+            (complex-reg (symbolicate "COMPLEX-" size "-REG"))
+            (real-reg (symbolicate size "-REG"))
+            (c-type (symbolicate "COMPLEX-" size "-FLOAT"))
+            (real-part (symbolicate "COMPLEX-" size "-REG-REAL-TN"))
+            (imag-part (symbolicate "COMPLEX-" size "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+           (:args (x :scs (,complex-reg))
+                  (y :scs (,complex-reg)))
+           (:results (r :scs (,complex-reg)))
+           (:arg-types ,c-type ,c-type)
+           (:result-types ,c-type)
+           (:policy :fast-safe)
+           (:note "inline complex float multiplication")
+           (:translate *)
+           (:temporary (:scs (,real-reg)) prod-1 prod-2 prod-3 prod-4)
+           (:generator ,cost
+             (let ((xr (,real-part x))
+                   (xi (,imag-part x))
+                   (yr (,real-part y))
+                   (yi (,imag-part y))
+                   (rr (,real-part r))
+                   (ri (,imag-part r)))
+               ;; All of the temps are needed in case the result TN happens to
+               ;; be the same as one of the arg TN's
+               (inst ,fmul prod-1 xr yr)
+               (inst ,fmul prod-2 xi yi)
+               (inst ,fmul prod-3 xr yi)
+               (inst ,fmul prod-4 xi yr)
+               (inst ,fsub rr prod-1 prod-2)
+               (inst ,fadd ri prod-3 prod-4)))))))
+
+  (frob single fmuls fadds fsubs 6)
+  (frob double fmuld faddd fsubd 6))
+
+(macrolet
+    ((frob (size fmul fadd fsub cost)
+       (let ((vop-name (symbolicate "*/COMPLEX-" size "-FLOAT"))
+            (complex-reg (symbolicate "COMPLEX-" size "-REG"))
+            (real-reg (symbolicate size "-REG"))
+            (c-type (symbolicate "COMPLEX-" size "-FLOAT"))
+            (real-part (symbolicate "COMPLEX-" size "-REG-REAL-TN"))
+            (imag-part (symbolicate "COMPLEX-" size "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+           (:args (x :scs (,complex-reg))
+                  (y :scs (,complex-reg)))
+           (:results (r :scs (,complex-reg)))
+           (:arg-types ,c-type ,c-type)
+           (:result-types ,c-type)
+           (:policy :fast-safe)
+           (:note "inline complex float multiplication")
+           (:translate *)
+           (:temporary (:scs (,real-reg)) p1 p2)
+           (:generator ,cost
+             (let ((xr (,real-part x))
+                   (xi (,imag-part x))
+                   (yr (,real-part y))
+                   (yi (,imag-part y))
+                   (rr (,real-part r))
+                   (ri (,imag-part r)))
+               (cond ((location= r x)
+                      (inst ,fmul p1 xr yr)
+                      (inst ,fmul p2 xr yi)
+                      (inst ,fmul rr xi yi)
+                      (inst ,fsub rr p1 xr)
+                      (inst ,fmul p1 xi yr)
+                      (inst ,fadd ri p2 p1))
+                     ((location= r y)
+                      (inst ,fmul p1 yr xr)
+                      (inst ,fmul p2 yr xi)
+                      (inst ,fmul rr yi xi)
+                      (inst ,fsub rr p1 rr)
+                      (inst ,fmul p1 yi xr)
+                      (inst ,fadd ri p2 p1))
+                     (t
+                      (inst ,fmul rr yr xr)
+                      (inst ,fmul ri xi yi)
+                      (inst ,fsub rr rr ri)
+                      (inst ,fmul p1 xr yi)
+                      (inst ,fmul ri xi yr)
+                      (inst ,fadd ri ri p1)))))))))
+
+  (frob single fmuls fadds fsubs 6)
+  (frob double fmuld faddd fsubd 6))
+
+;; Multiply a complex by a float.  The case of float * complex is
+;; handled by a deftransform to convert it to the complex*float case.
+(macrolet
+    ((frob (float-type fmul mov cost)
+       (let* ((vop-name (symbolicate "COMPLEX-"
+                                    float-type
+                                    "-FLOAT-*-"
+                                    float-type
+                                    "-FLOAT"))
+             (vop-name-r (symbolicate float-type
+                                      "-FLOAT-*-COMPLEX-"
+                                      float-type
+                                      "-FLOAT"))
+             (complex-sc-type (symbolicate "COMPLEX-" float-type "-REG"))
+             (real-sc-type (symbolicate float-type "-REG"))
+             (c-type (symbolicate "COMPLEX-" float-type "-FLOAT"))
+             (r-type (symbolicate float-type "-FLOAT"))
+             (real-part (symbolicate "COMPLEX-" float-type "-REG-REAL-TN"))
+             (imag-part (symbolicate "COMPLEX-" float-type "-REG-IMAG-TN")))
+        `(progn
+          ;; Complex * float
+          (define-vop (,vop-name)
+            (:args (x :scs (,complex-sc-type))
+                   (y :scs (,real-sc-type)))
+            (:results (r :scs (,complex-sc-type)))
+            (:arg-types ,c-type ,r-type)
+            (:result-types ,c-type)
+            (:policy :fast-safe)
+            (:note "inline complex float arithmetic")
+            (:translate *)
+            (:temporary (:scs (,real-sc-type)) temp)
+            (:generator ,cost
+             (let ((xr (,real-part x))
+                   (xi (,imag-part x))
+                   (rr (,real-part r))
+                   (ri (,imag-part r)))
+               (cond ((location= y rr)
+                      (inst ,fmul temp xr y) ; xr * y
+                      (inst ,fmul ri xi y) ; xi * yi
+                      (,@mov rr temp))
+                     (t
+                      (inst ,fmul rr xr y)
+                      (inst ,fmul ri xi y))))))
+          ;; Float * complex
+          (define-vop (,vop-name-r)
+            (:args (y :scs (,real-sc-type))
+                   (x :scs (,complex-sc-type)))
+            (:results (r :scs (,complex-sc-type)))
+            (:arg-types ,r-type ,c-type)
+            (:result-types ,c-type)
+            (:policy :fast-safe)
+            (:note "inline complex float arithmetic")
+            (:translate *)
+            (:temporary (:scs (,real-sc-type)) temp)
+            (:generator ,cost
+             (let ((xr (,real-part x))
+                   (xi (,imag-part x))
+                   (rr (,real-part r))
+                   (ri (,imag-part r)))
+               (cond ((location= y rr)
+                      (inst ,fmul temp xr y) ; xr * y
+                      (inst ,fmul ri xi y) ; xi * yi
+                      (,@mov rr temp))
+                     (t
+                      (inst ,fmul rr xr y)
+                      (inst ,fmul ri xi y))))))))))
+  (frob single fmuls (inst fmovs) 4)
+  (frob double fmuld (move-double-reg) 4))
+
+
+;; Divide a complex by a complex
+
+;; Here's how we do a complex division
+;;
+;; Compute (xr + i*xi)/(yr + i*yi)
+;;
+;; Assume |yi| < |yr|.  Then
+;;
+;; (xr + i*xi)      (xr + i*xi)
+;; ----------- = -----------------
+;; (yr + i*yi)   yr*(1 + i*(yi/yr))
+;;
+;;               (xr + i*xi)*(1 - i*(yi/yr))
+;;             = ---------------------------
+;;                   yr*(1 + (yi/yr)^2)
+;;
+;;               (xr + (yi/yr)*xi) + i*(xi - (yi/yr)*xr)
+;;             = --------------------------------------
+;;                        yr + (yi/yr)*yi
+;;
+;;
+;; We do the similar thing when |yi| > |yr|.  The result is
+;;
+;;     
+;; (xr + i*xi)      (xr + i*xi)
+;; ----------- = -----------------
+;; (yr + i*yi)   yi*((yr/yi) + i)
+;;
+;;               (xr + i*xi)*((yr/yi) - i)
+;;             = -------------------------
+;;                  yi*((yr/yi)^2 + 1)
+;;
+;;               (xr*(yr/yi) + xi) + i*(xi*(yr/yi) - xr)
+;;             = ---------------------------------------
+;;                       yi + (yr/yi)*yr
+;;
+
+#+nil
+(macrolet
+    ((frob (float-type fcmp fadd fsub fmul fdiv fabs fmov cost)
+       (let ((vop-name (symbolicate "//COMPLEX-" float-type "-FLOAT"))
+            (complex-reg (symbolicate "COMPLEX-" float-type "-REG"))
+            (real-reg (symbolicate float-type "-REG"))
+            (c-type (symbolicate "COMPLEX-" float-type "-FLOAT"))
+            (real-part (symbolicate "COMPLEX-" float-type "-REG-REAL-TN"))
+            (imag-part (symbolicate "COMPLEX-" float-type "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+           (:args (x :scs (,complex-reg))
+                  (y :scs (,complex-reg)))
+           (:results (r :scs (,complex-reg)))
+           (:arg-types ,c-type ,c-type)
+           (:result-types ,c-type)
+           (:policy :fast-safe)
+           (:note "inline complex float division")
+           (:translate /)
+           (:temporary (:sc ,real-reg) ratio)
+           (:temporary (:sc ,real-reg) den)
+           (:temporary (:sc ,real-reg) temp-r)
+           (:temporary (:sc ,real-reg) temp-i)
+           (:generator ,cost
+             (let ((xr (,real-part x))
+                   (xi (,imag-part x))
+                   (yr (,real-part y))
+                   (yi (,imag-part y))
+                   (rr (,real-part r))
+                   (ri (,imag-part r))
+                   (bigger (gen-label))
+                   (done (gen-label)))
+               (,@fabs ratio yr)
+               (,@fabs den yi)
+               (inst ,fcmp ratio den)
+               #!-:sparc-v9 (inst nop)
+               (inst fb :ge bigger)
+               (inst nop)
+               ;; The case of |yi| <= |yr|
+               (inst ,fdiv ratio yi yr) ; ratio = yi/yr
+               (inst ,fmul den ratio yi)
+               (inst ,fadd den den yr) ; den = yr + (yi/yr)*yi
+
+               (inst ,fmul temp-r ratio xi)
+               (inst ,fadd temp-r temp-r xr) ; temp-r = xr + (yi/yr)*xi
+               (inst ,fdiv temp-r temp-r den)
+
+               (inst ,fmul temp-i ratio xr)
+               (inst ,fsub temp-i xi temp-i) ; temp-i = xi - (yi/yr)*xr
+               (inst b done)
+               (inst ,fdiv temp-i temp-i den)
+
+               (emit-label bigger)
+               ;; The case of |yi| > |yr|
+               (inst ,fdiv ratio yr yi) ; ratio = yr/yi
+               (inst ,fmul den ratio yr)
+               (inst ,fadd den den yi) ; den = yi + (yr/yi)*yr
+
+               (inst ,fmul temp-r ratio xr)
+               (inst ,fadd temp-r temp-r xi) ; temp-r = xi + xr*(yr/yi)
+               (inst ,fdiv temp-r temp-r den)
+
+               (inst ,fmul temp-i ratio xi)
+               (inst ,fsub temp-i temp-i xr) ; temp-i = xi*(yr/yi) - xr
+               (inst ,fdiv temp-i temp-i den)
+
+               (emit-label done)
+               (unless (location= temp-r rr)
+                 (,@fmov rr temp-r))
+               (unless (location= temp-i ri)
+                 (,@fmov ri temp-i))
+               ))))))
+
+  (frob single fcmps fadds fsubs fmuls fdivs (inst fabss) (inst fmovs) 15)
+  (frob double fcmpd faddd fsubd fmuld fdivd (abs-double-reg) (move-double-reg) 15))
+
+(macrolet
+    ((frob (float-type fcmp fadd fsub fmul fdiv fabs cost)
+       (let ((vop-name (symbolicate "//COMPLEX-" float-type "-FLOAT"))
+            (complex-reg (symbolicate "COMPLEX-" float-type "-REG"))
+            (real-reg (symbolicate float-type "-REG"))
+            (c-type (symbolicate "COMPLEX-" float-type "-FLOAT"))
+            (real-part (symbolicate "COMPLEX-" float-type "-REG-REAL-TN"))
+            (imag-part (symbolicate "COMPLEX-" float-type "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+           (:args (x :scs (,complex-reg))
+                  (y :scs (,complex-reg)))
+           (:results (r :scs (,complex-reg)))
+           (:arg-types ,c-type ,c-type)
+           (:result-types ,c-type)
+           (:policy :fast-safe)
+           (:note "inline complex float division")
+           (:translate /)
+           (:temporary (:sc ,real-reg) ratio)
+           (:temporary (:sc ,real-reg) den)
+           (:temporary (:sc ,real-reg) temp-r)
+           (:temporary (:sc ,real-reg) temp-i)
+           (:generator ,cost
+             (let ((xr (,real-part x))
+                   (xi (,imag-part x))
+                   (yr (,real-part y))
+                   (yi (,imag-part y))
+                   (rr (,real-part r))
+                   (ri (,imag-part r))
+                   (bigger (gen-label))
+                   (done (gen-label)))
+               (,@fabs ratio yr)
+               (,@fabs den yi)
+               (inst ,fcmp ratio den)
+               #!-:sparc-v9 (inst nop)
+               (inst fb :ge bigger)
+               (inst nop)
+               ;; The case of |yi| <= |yr|
+               (inst ,fdiv ratio yi yr) ; ratio = yi/yr
+               (inst ,fmul den ratio yi)
+               (inst ,fmul temp-r ratio xi)
+               (inst ,fmul temp-i ratio xr)
+
+               (inst ,fadd den den yr) ; den = yr + (yi/yr)*yi
+               (inst ,fadd temp-r temp-r xr) ; temp-r = xr + (yi/yr)*xi
+               (inst b done)
+               (inst ,fsub temp-i xi temp-i) ; temp-i = xi - (yi/yr)*xr
+
+
+               (emit-label bigger)
+               ;; The case of |yi| > |yr|
+               (inst ,fdiv ratio yr yi) ; ratio = yr/yi
+               (inst ,fmul den ratio yr)
+               (inst ,fmul temp-r ratio xr)
+               (inst ,fmul temp-i ratio xi)
+
+               (inst ,fadd den den yi) ; den = yi + (yr/yi)*yr
+               (inst ,fadd temp-r temp-r xi) ; temp-r = xi + xr*(yr/yi)
+
+               (inst ,fsub temp-i temp-i xr) ; temp-i = xi*(yr/yi) - xr
+
+               (emit-label done)
+
+               (inst ,fdiv rr temp-r den)
+               (inst ,fdiv ri temp-i den)
+               ))))))
+
+  (frob single fcmps fadds fsubs fmuls fdivs (inst fabss) 15)
+  (frob double fcmpd faddd fsubd fmuld fdivd (abs-double-reg) 15))
+
+
+;; Divide a complex by a real
+(macrolet
+    ((frob (float-type fdiv cost)
+       (let* ((vop-name (symbolicate "COMPLEX-" float-type "-FLOAT-/-" float-type "-FLOAT"))
+             (complex-sc-type (symbolicate "COMPLEX-" float-type "-REG"))
+             (real-sc-type (symbolicate float-type "-REG"))
+             (c-type (symbolicate "COMPLEX-" float-type "-FLOAT"))
+             (r-type (symbolicate float-type "-FLOAT"))
+             (real-part (symbolicate "COMPLEX-" float-type "-REG-REAL-TN"))
+             (imag-part (symbolicate "COMPLEX-" float-type "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+          (:args (x :scs (,complex-sc-type)) (y :scs (,real-sc-type)))
+          (:results (r :scs (,complex-sc-type)))
+          (:arg-types ,c-type ,r-type)
+          (:result-types ,c-type)
+          (:policy :fast-safe)
+          (:note "inline complex float arithmetic")
+          (:translate /)
+          (:generator ,cost
+           (let ((xr (,real-part x))
+                 (xi (,imag-part x))
+                 (rr (,real-part r))
+                 (ri (,imag-part r)))
+             (inst ,fdiv rr xr y)      ; xr * y
+             (inst ,fdiv ri xi y)      ; xi * yi
+             ))))))
+  (frob single fdivs 2)
+  (frob double fdivd 2))
+
+;; Divide a real by a complex
+
+(macrolet
+    ((frob (float-type fcmp fadd fmul fdiv fneg fabs cost)
+       (let ((vop-name (symbolicate float-type "-FLOAT-/-COMPLEX-" float-type "-FLOAT"))
+            (complex-reg (symbolicate "COMPLEX-" float-type "-REG"))
+            (real-reg (symbolicate float-type "-REG"))
+            (r-type (symbolicate float-type "-FLOAT"))
+            (c-type (symbolicate "COMPLEX-" float-type "-FLOAT"))
+            (real-tn (symbolicate "COMPLEX-" float-type "-REG-REAL-TN"))
+            (imag-tn (symbolicate "COMPLEX-" float-type "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+           (:args (x :scs (,real-reg))
+                  (y :scs (,complex-reg)))
+           (:results (r :scs (,complex-reg)))
+           (:arg-types ,r-type ,c-type)
+           (:result-types ,c-type)
+           (:policy :fast-safe)
+           (:note "inline complex float division")
+           (:translate /)
+           (:temporary (:sc ,real-reg) ratio)
+           (:temporary (:sc ,real-reg) den)
+           (:temporary (:sc ,real-reg) temp)
+           (:generator ,cost
+             (let ((yr (,real-tn y))
+                   (yi (,imag-tn y))
+                   (rr (,real-tn r))
+                   (ri (,imag-tn r))
+                   (bigger (gen-label))
+                   (done (gen-label)))
+               (,@fabs ratio yr)
+               (,@fabs den yi)
+               (inst ,fcmp ratio den)
+               #!-:sparc-v9 (inst nop)
+               (inst fb :ge bigger)
+               (inst nop)
+               ;; The case of |yi| <= |yr|
+               (inst ,fdiv ratio yi yr) ; ratio = yi/yr
+               (inst ,fmul den ratio yi)
+               (inst ,fadd den den yr) ; den = yr + (yi/yr)*yi
+
+               (inst ,fmul temp ratio x) ; temp = (yi/yr)*x
+               (inst ,fdiv rr x den)   ; rr = x/den
+               (inst b done)
+               (inst ,fdiv temp temp den) ; temp = (yi/yr)*x/den
+
+               (emit-label bigger)
+               ;; The case of |yi| > |yr|
+               (inst ,fdiv ratio yr yi) ; ratio = yr/yi
+               (inst ,fmul den ratio yr)
+               (inst ,fadd den den yi) ; den = yi + (yr/yi)*yr
+
+               (inst ,fmul temp ratio x) ; temp = (yr/yi)*x
+               (inst ,fdiv rr temp den) ; rr = (yr/yi)*x/den
+               (inst ,fdiv temp x den) ; temp = x/den
+               (emit-label done)
+
+               (,@fneg ri temp)))))))
+
+  (frob single fcmps fadds fmuls fdivs (inst fnegs) (inst fabss) 10)
+  (frob double fcmpd faddd fmuld fdivd (negate-double-reg) (abs-double-reg) 10))
+
+;; Conjugate of a complex number
+
+(macrolet
+    ((frob (float-type fneg fmov cost)
+       (let ((vop-name (symbolicate "CONJUGATE/COMPLEX-" float-type "-FLOAT"))
+            (complex-reg (symbolicate "COMPLEX-" float-type "-REG"))
+            (c-type (symbolicate "COMPLEX-" float-type "-FLOAT"))
+            (real-part (symbolicate "COMPLEX-" float-type "-REG-REAL-TN"))
+            (imag-part (symbolicate "COMPLEX-" float-type "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+           (:args (x :scs (,complex-reg)))
+           (:results (r :scs (,complex-reg)))
+           (:arg-types ,c-type)
+           (:result-types ,c-type)
+           (:policy :fast-safe)
+           (:note "inline complex conjugate")
+           (:translate conjugate)
+           (:generator ,cost
+             (let ((xr (,real-part x))
+                   (xi (,imag-part x))
+                   (rr (,real-part r))
+                   (ri (,imag-part r)))
+               (,@fneg ri xi)
+               (unless (location= rr xr)
+                 (,@fmov rr xr))))))))
+
+  (frob single (inst fnegs) (inst fmovs) 4)
+  (frob double (negate-double-reg) (move-double-reg) 4))
+
+;; Compare a float with a complex or a complex with a float
+#+nil
+(macrolet
+    ((frob (name name-r f-type c-type)
+       `(progn
+        (defknown ,name (,f-type ,c-type) t)
+        (defknown ,name-r (,c-type ,f-type) t)
+        (defun ,name (x y)
+          (declare (type ,f-type x)
+                   (type ,c-type y))
+          (,name x y))
+        (defun ,name-r (x y)
+          (declare (type ,c-type x)
+                   (type ,f-type y))
+          (,name-r x y))
+        )))
+  (frob %compare-complex-single-single %compare-single-complex-single
+       single-float (complex single-float))
+  (frob %compare-complex-double-double %compare-double-complex-double
+       double-float (complex double-float)))
+          
+#+nil
+(macrolet
+    ((frob (trans-1 trans-2 float-type fcmp fsub)
+       (let ((vop-name
+             (symbolicate "COMPLEX-" float-type "-FLOAT-"
+                          float-type "-FLOAT-COMPARE"))
+            (vop-name-r
+             (symbolicate float-type "-FLOAT-COMPLEX-"
+                          float-type "-FLOAT-COMPARE"))
+            (complex-reg (symbolicate "COMPLEX-" float-type "-REG"))
+            (real-reg (symbolicate float-type "-REG"))
+            (c-type (symbolicate "COMPLEX-" float-type "-FLOAT"))
+            (r-type (symbolicate float-type "-FLOAT"))
+            (real-part (symbolicate "COMPLEX-" float-type "-REG-REAL-TN"))
+            (imag-part (symbolicate "COMPLEX-" float-type "-REG-IMAG-TN")))
+        `(progn
+           ;; (= float complex)
+           (define-vop (,vop-name)
+             (:args (x :scs (,real-reg))
+                    (y :scs (,complex-reg)))
+             (:arg-types ,r-type ,c-type)
+             (:translate ,trans-1)
+             (:conditional)
+             (:info target not-p)
+             (:policy :fast-safe)
+             (:note "inline complex float/float comparison")
+             (:vop-var vop)
+             (:save-p :compute-only)
+             (:temporary (:sc ,real-reg) fp-zero)
+             (:guard #!-:sparc-v9 nil #!+:sparc-v9 t)
+             (:generator 6
+              (note-this-location vop :internal-error)
+              (let ((yr (,real-part y))
+                    (yi (,imag-part y)))
+                ;; Set fp-zero to zero
+                (inst ,fsub fp-zero fp-zero fp-zero)
+                (inst ,fcmp x yr)
+                (inst nop)
+                (inst fb (if not-p :ne :eq) target #!+sparc-v9 :fcc0 #!+sparc-v9 :pn)
+                (inst ,fcmp yi fp-zero)
+                (inst nop)
+                (inst fb (if not-p :ne :eq) target #!+sparc-v9 :fcc0 #!+sparc-v9 :pn)
+                (inst nop))))
+           ;; (= complex float)
+           (define-vop (,vop-name-r)
+             (:args (y :scs (,complex-reg))
+                    (x :scs (,real-reg)))
+             (:arg-types ,c-type ,r-type)
+             (:translate ,trans-2)
+             (:conditional)
+             (:info target not-p)
+             (:policy :fast-safe)
+             (:note "inline complex float/float comparison")
+             (:vop-var vop)
+             (:save-p :compute-only)
+             (:temporary (:sc ,real-reg) fp-zero)
+             (:guard #!-:sparc-v9 t #!+:sparc-v9 nil)
+             (:generator 6
+              (note-this-location vop :internal-error)
+              (let ((yr (,real-part y))
+                    (yi (,imag-part y)))
+                ;; Set fp-zero to zero
+                (inst ,fsub fp-zero fp-zero fp-zero)
+                (inst ,fcmp x yr)
+                (inst nop)
+                (inst fb (if not-p :ne :eq) target #!+sparc-v9 :fcc0 #!+sparc-v9 :pn)
+                (inst ,fcmp yi fp-zero)
+                (inst nop)
+                (inst fb (if not-p :ne :eq) target #!+sparc-v9 :fcc0 #!+sparc-v9 :pn)
+                (inst nop))))))))
+  (frob %compare-complex-single-single %compare-single-complex-single
+       single fcmps fsubs)
+  (frob %compare-complex-double-double %compare-double-complex-double
+       double fcmpd fsubd))
+
+;; Compare two complex numbers for equality
+(macrolet
+    ((frob (float-type fcmp)
+       (let ((vop-name
+             (symbolicate "COMPLEX-" float-type "-FLOAT-COMPARE"))
+            (complex-reg (symbolicate "COMPLEX-" float-type "-REG"))
+            (c-type (symbolicate "COMPLEX-" float-type "-FLOAT"))
+            (real-part (symbolicate "COMPLEX-" float-type "-REG-REAL-TN"))
+            (imag-part (symbolicate "COMPLEX-" float-type "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+           (:args (x :scs (,complex-reg))
+                  (y :scs (,complex-reg)))
+           (:arg-types ,c-type ,c-type)
+           (:translate =)
+           (:conditional)
+           (:info target not-p)
+           (:policy :fast-safe)
+           (:note "inline complex float comparison")
+           (:vop-var vop)
+           (:save-p :compute-only)
+           (:guard #!-:sparc-v9 t #!+:sparc-v9 nil)
+           (:generator 6
+             (note-this-location vop :internal-error)
+             (let ((xr (,real-part x))
+                   (xi (,imag-part x))
+                   (yr (,real-part y))
+                   (yi (,imag-part y)))
+               (inst ,fcmp xr yr)
+               (inst nop)
+               (inst fb (if not-p :ne :eq) target #!+sparc-v9 :fcc0 #!+sparc-v9 :pn)
+               (inst ,fcmp xi yi)
+               (inst nop)
+               (inst fb (if not-p :ne :eq) target #!+sparc-v9 :fcc0 #!+sparc-v9 :pn)
+               (inst nop)))))))
+  (frob single fcmps)
+  (frob double fcmpd))
+
+;; Compare a complex with a complex, for V9
+(macrolet
+    ((frob (float-type fcmp)
+       (let ((vop-name
+             (symbolicate "V9-COMPLEX-" float-type "-FLOAT-COMPARE"))
+            (complex-reg (symbolicate "COMPLEX-" float-type "-REG"))
+            (c-type (symbolicate "COMPLEX-" float-type "-FLOAT"))
+            (real-part (symbolicate "COMPLEX-" float-type "-REG-REAL-TN"))
+            (imag-part (symbolicate "COMPLEX-" float-type "-REG-IMAG-TN")))
+        `(define-vop (,vop-name)
+           (:args (x :scs (,complex-reg))
+                  (y :scs (,complex-reg)))
+           (:arg-types ,c-type ,c-type)
+           (:translate =)
+           (:conditional)
+           (:info target not-p)
+           (:policy :fast-safe)
+           (:note "inline complex float comparison")
+           (:vop-var vop)
+           (:save-p :compute-only)
+           (:temporary (:sc descriptor-reg) true)
+           (:guard #!+:sparc-v9 t #!-:sparc-v9 nil)
+           (:generator 6
+             (note-this-location vop :internal-error)
+             (let ((xr (,real-part x))
+                   (xi (,imag-part x))
+                   (yr (,real-part y))
+                   (yi (,imag-part y)))
+               ;; Assume comparison is true
+               (load-symbol true t)
+               (inst ,fcmp xr yr)
+               (inst cmove (if not-p :eq :ne) true null-tn :fcc0)
+               (inst ,fcmp xi yi)
+               (inst cmove (if not-p :eq :ne) true null-tn :fcc0)
+               (inst cmp true null-tn)
+               (inst b (if not-p :eq :ne) target :pt)
+               (inst nop)))))))
+  (frob single fcmps)
+  (frob double fcmpd))
+
+) ; end progn complex-fp-vops
+
+#!+sparc-v9
+(progn
+
+;; Vops to take advantage of the conditional move instruction
+;; available on the Sparc V9
+  
+(defknown (%%max %%min) ((or (unsigned-byte #.n-word-bits)
+                            (signed-byte #.n-word-bits)
+                            single-float double-float)
+                        (or (unsigned-byte #.n-word-bits)
+                            (signed-byte #.n-word-bits)
+                            single-float double-float))
+  (or (unsigned-byte #.n-word-bits)
+      (signed-byte #.n-word-bits)
+      single-float double-float)
+  (movable foldable flushable))
+
+;; We need these definitions for byte-compiled code
+(defun %%min (x y)
+  (declare (type (or (unsigned-byte 32) (signed-byte 32)
+                    single-float double-float) x y))
+  (if (< x y)
+      x y))
+
+(defun %%max (x y)
+  (declare (type (or (unsigned-byte 32) (signed-byte 32)
+                    single-float double-float) x y))
+  (if (> x y)
+      x y))
+  
+(macrolet
+    ((frob (name sc-type type compare cmov cost cc max min note)
+       (let ((vop-name (symbolicate name "-" type "=>" type))
+            (trans-name (symbolicate "%%" name)))
+        `(define-vop (,vop-name)
+           (:args (x :scs (,sc-type))
+                  (y :scs (,sc-type)))
+           (:results (r :scs (,sc-type)))
+           (:arg-types ,type ,type)
+           (:result-types ,type)
+           (:policy :fast-safe)
+           (:note ,note)
+           (:translate ,trans-name)
+           (:guard #!+:sparc-v9 t #!-:sparc-v9 nil)
+           (:generator ,cost
+             (inst ,compare x y)
+             (cond ((location= r x)
+                    ;; If x < y, need to move y to r, otherwise r already has
+                    ;; the max.
+                    (inst ,cmov ,min r y ,cc))
+                   ((location= r y)
+                    ;; If x > y, need to move x to r, otherwise r already has
+                    ;; the max.
+                    (inst ,cmov ,max r x ,cc))
+                   (t
+                    ;; It doesn't matter what R is, just copy the min to R.
+                    (inst ,cmov ,max r x ,cc)
+                    (inst ,cmov ,min r y ,cc))))))))
+  (frob max single-reg single-float fcmps cfmovs 3
+       :fcc0 :ge :l "inline float max")
+  (frob max double-reg double-float fcmpd cfmovd 3
+       :fcc0 :ge :l "inline float max")
+  (frob min single-reg single-float fcmps cfmovs 3
+       :fcc0 :l :ge "inline float min")
+  (frob min double-reg double-float fcmpd cfmovd 3
+       :fcc0 :l :ge "inline float min")
+  ;; Strictly speaking these aren't float ops, but it's convenient to
+  ;; do them here.
+  ;;
+  ;; The cost is here is the worst case number of instructions.  For
+  ;; 32-bit integer operands, we add 2 more to account for the
+  ;; untagging of fixnums, if necessary.
+  (frob max signed-reg signed-num cmp cmove 5
+       :icc :ge :lt "inline (signed-byte 32) max")
+  (frob max unsigned-reg unsigned-num cmp cmove 5
+       :icc :ge :lt "inline (unsigned-byte 32) max")
+  ;; For fixnums, make the cost lower so we don't have to untag the
+  ;; numbers.
+  (frob max any-reg tagged-num cmp cmove 3
+       :icc :ge :lt "inline fixnum max")
+  (frob min signed-reg signed-num cmp cmove 5
+       :icc :lt :ge "inline (signed-byte 32) min")
+  (frob min unsigned-reg unsigned-num cmp cmove 5
+       :icc :lt :ge "inline (unsigned-byte 32) min")
+  ;; For fixnums, make the cost lower so we don't have to untag the
+  ;; numbers.
+  (frob min any-reg tagged-num cmp cmove 3
+       :icc :lt :ge "inline fixnum min"))
+          
+#+nil
+(define-vop (max-boxed-double-float=>boxed-double-float)
+  (:args (x :scs (descriptor-reg))
+        (y :scs (descriptor-reg)))
+  (:results (r :scs (descriptor-reg)))
+  (:arg-types double-float double-float)
+  (:result-types double-float)
+  (:policy :fast-safe)
+  (:note "inline float max/min")
+  (:translate %max-double-float)
+  (:temporary (:scs (double-reg)) xval)
+  (:temporary (:scs (double-reg)) yval)
+  (:guard #!+:sparc-v9 t #!-:sparc-v9 nil)
+  (:vop-var vop)
+  (:generator 3
+    (let ((offset (- (* double-float-value-slot n-word-bytes)
+                    other-pointer-lowtag)))
+      (inst lddf xval x offset)
+      (inst lddf yval y offset)
+      (inst fcmpd xval yval)
+      (cond ((location= r x)
+            ;; If x < y, need to move y to r, otherwise r already has
+            ;; the max.
+            (inst cmove :l r y :fcc0))
+           ((location= r y)
+            ;; If x > y, need to move x to r, otherwise r already has
+            ;; the max.
+            (inst cmove :ge r x :fcc0))
+           (t
+            ;; It doesn't matter what R is, just copy the min to R.
+            (inst cmove :ge r x :fcc0)
+            (inst cmove :l r y :fcc0))))))
+    
+) ; PROGN
+
+(in-package "SB!C")
+;;; FIXME
+#| #!+sparc-v9 |#
+#+nil
+(progn
+;;; The sparc-v9 architecture has conditional move instructions that
+;;; can be used.  This should be faster than using the obvious if
+;;; expression since we don't have to do branches.
+  
+(def-source-transform min (&rest args)
+  (case (length args)
+    ((0 2) (values nil t))
+    (1 `(values ,(first args)))
+    (t (sb!c::associate-arguments 'min (first args) (rest args)))))
+
+(def-source-transform max (&rest args)
+  (case (length args)
+    ((0 2) (values nil t))
+    (1 `(values ,(first args)))
+    (t (sb!c::associate-arguments 'max (first args) (rest args)))))
+
+;; Derive the types of max and min
+(defoptimizer (max derive-type) ((x y))
+  (multiple-value-bind (definitely-< definitely->=)
+      (ir1-transform-<-helper x y)
+    (cond (definitely-<
+             (continuation-type y))
+         (definitely->=
+             (continuation-type x))
+         (t
+          (make-canonical-union-type (list (continuation-type x)
+                                           (continuation-type y)))))))
+
+(defoptimizer (min derive-type) ((x y))
+  (multiple-value-bind (definitely-< definitely->=)
+      (ir1-transform-<-helper x y)
+    (cond (definitely-<
+             (continuation-type x))
+         (definitely->=
+             (continuation-type y))
+         (t
+          (make-canonical-union-type (list (continuation-type x)
+                                           (continuation-type y)))))))
+
+(deftransform max ((x y) (number number) * :when :both)
+  (let ((x-type (continuation-type x))
+       (y-type (continuation-type y))
+       (signed (specifier-type '(signed-byte #.sb!vm:n-word-bits)))
+       (unsigned (specifier-type '(unsigned-byte #.sb!vm:n-word-bits)))
+       (d-float (specifier-type 'double-float))
+       (s-float (specifier-type 'single-float)))
+    ;; Use %%max if both args are good types of the same type.  As a
+    ;; last resort, use the obvious comparison to select the desired
+    ;; element.
+    (cond ((and (csubtypep x-type signed)
+               (csubtypep y-type signed))
+          `(%%max x y))
+         ((and (csubtypep x-type unsigned)
+               (csubtypep y-type unsigned))
+          `(%%max x y))
+         ((and (csubtypep x-type d-float)
+               (csubtypep y-type d-float))
+          `(%%max x y))
+         ((and (csubtypep x-type s-float)
+               (csubtypep y-type s-float))
+          `(%%max x y))
+         (t
+          (let ((arg1 (gensym))
+                (arg2 (gensym)))
+            `(let ((,arg1 x)
+                   (,arg2 y))
+              (if (> ,arg1 ,arg2)
+                  ,arg1 ,arg2)))))))
+
+(deftransform min ((x y) (real real) * :when :both)
+  (let ((x-type (continuation-type x))
+       (y-type (continuation-type y))
+       (signed (specifier-type '(signed-byte #.sb!vm:n-word-bits)))
+       (unsigned (specifier-type '(unsigned-byte #.sb!vm:n-word-bits)))
+       (d-float (specifier-type 'double-float))
+       (s-float (specifier-type 'single-float)))
+    (cond ((and (csubtypep x-type signed)
+               (csubtypep y-type signed))
+          `(%%min x y))
+         ((and (csubtypep x-type unsigned)
+               (csubtypep y-type unsigned))
+          `(%%min x y))
+         ((and (csubtypep x-type d-float)
+               (csubtypep y-type d-float))
+          `(%%min x y))
+         ((and (csubtypep x-type s-float)
+               (csubtypep y-type s-float))
+          `(%%min x y))
+         (t
+          (let ((arg1 (gensym))
+                (arg2 (gensym)))
+            `(let ((,arg1 x)
+                   (,arg2 y))
+               (if (< ,arg1 ,arg2)
+                   ,arg1 ,arg2)))))))
+
+) ; PROGN
+
diff --git a/src/compiler/sparc/insts.lisp b/src/compiler/sparc/insts.lisp
new file mode 100644 (file)
index 0000000..1da4730
--- /dev/null
@@ -0,0 +1,2161 @@
+;;;; the instruction set definition for the Sparc
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+;;;FIXME: the analogue is commented out in alpha/insts.lisp
+;;;(def-assembler-params
+;;;    :scheduler-p t
+;;;  :max-locations 100)
+\f
+;;; Constants, types, conversion functions, some disassembler stuff.
+(defun reg-tn-encoding (tn)
+  (declare (type tn tn))
+  (sc-case tn
+    (zero zero-offset)
+    (null null-offset)
+    (t
+     (if (eq (sb-name (sc-sb (tn-sc tn))) 'registers)
+        (tn-offset tn)
+        (error "~S isn't a register." tn)))))
+
+(defun fp-reg-tn-encoding (tn)
+  (declare (type tn tn))
+  (unless (eq (sb-name (sc-sb (tn-sc tn))) 'float-registers)
+    (error "~S isn't a floating-point register." tn))
+  (let ((offset (tn-offset tn)))
+    (cond ((> offset 31)
+          ;; Use the sparc v9 double float register encoding.
+          #!-:sparc-v9 (error ":sparc-v9 should be on the target features")
+          ;; (assert (backend-featurep :sparc-v9))
+          ;; No single register encoding greater than reg 31.
+          (assert (zerop (mod offset 2)))
+          ;; Upper bit of the register number is encoded in the low bit.
+          (1+ (- offset 32)))
+         (t
+          (tn-offset tn)))))
+
+;;;(sb!disassem:set-disassem-params :instruction-alignment 32
+;;;                             :opcode-column-width 11)
+
+(defvar *disassem-use-lisp-reg-names* t
+  #!+sb-doc
+  "If non-NIL, print registers using the Lisp register names.
+Otherwise, use the Sparc register names")
+
+(!def-vm-support-routine location-number (loc)
+  (etypecase loc
+    (null)
+    (number)
+    (fixup)
+    (tn
+     (ecase (sb-name (sc-sb (tn-sc loc)))
+       (registers
+       (unless (zerop (tn-offset loc))
+         (tn-offset loc)))
+       (float-registers
+       (sc-case loc
+         (single-reg
+          (+ (tn-offset loc) 32))
+         (double-reg
+          (let ((offset (tn-offset loc)))
+            (assert (zerop (mod offset 2)))
+            (values (+ offset 32) 2)))
+         #!+long-float
+         (long-reg
+          (let ((offset (tn-offset loc)))
+            (assert (zerop (mod offset 4)))
+            (values (+ offset 32) 4)))))
+       (control-registers
+       96)
+       (immediate-constant
+       nil)))
+    (symbol
+     (ecase loc
+       (:memory 0)
+       (:psr 97)
+       (:fsr 98)
+       (:y 99)))))
+
+;;; symbols used for disassembly printing
+(defparameter reg-symbols
+  (map 'vector
+       (lambda (name)
+          (cond ((null name) nil)
+                (t (make-symbol (concatenate 'string "%" name)))))
+       *register-names*)
+  #!+sb-doc "The Lisp names for the Sparc integer registers")
+
+(defparameter sparc-reg-symbols
+  #("%G0" "%G1" "%G2" "%G3" "%G4" "%G5" NIL NIL
+    "%O0" "%O1" "%O2" "%O3" "%O4" "%O5" "%O6" "%O7"
+    "%L0" "%L1" "%L2" "%L3" "%L4" "%L5" "%L6" "%L7"
+    "%I0" "%I1" "%I2" "%I3" "%I4" "%I5" NIL "%I7")
+  #!+sb-doc "The standard names for the Sparc integer registers")
+    
+(defun get-reg-name (index)
+  (if *disassem-use-lisp-reg-names*
+      (aref reg-symbols index)
+      (aref sparc-reg-symbols index)))
+
+(defvar *note-sethi-inst* nil
+  "An alist for the disassembler indicating the target register and
+value used in a SETHI instruction.  This is used to make annotations
+about function addresses and register values.")
+
+(defvar *pseudo-atomic-set* nil)
+
+(defun sign-extend-immed-value (val)
+  ;; val is a 13-bit signed number.  Extend the sign appropriately.
+  (if (logbitp 12 val)
+      (- val (ash 1 13))
+      val))
+
+;;; Oh, come on, this is ridiculous. I'm not going to solve
+;;; bootstrapping issues for a disassembly note. Does this make me
+;;; lazy? Christophe, 2001-09-02. FIXME
+#+nil
+(macrolet
+    ((frob (&rest names)
+       (let ((results (mapcar (lambda (n)
+                                 (let ((nn (intern (concatenate 'string (string n)
+                                                                "-TYPE"))))
+                                   `(,(eval nn) ,nn)))
+                             names)))
+        `(eval-when (:compile-toplevel :load-toplevel :execute)
+          (defconstant header-word-type-alist
+            ',results)))))
+  ;; This is the same list as in objdefs.
+  (frob bignum
+       ratio
+       single-float
+       double-float
+       #!+long-float long-float
+       complex
+       complex-single-float
+       complex-double-float
+       #!+long-float complex-long-float
+  
+       simple-array
+       simple-string
+       simple-bit-vector
+       simple-vector
+       simple-array-unsigned-byte-2
+       simple-array-unsigned-byte-4
+       simple-array-unsigned-byte-8
+       simple-array-unsigned-byte-16
+       simple-array-unsigned-byte-32
+       simple-array-signed-byte-8
+       simple-array-signed-byte-16
+       simple-array-signed-byte-30
+       simple-array-signed-byte-32
+       simple-array-single-float
+       simple-array-double-float
+       #!+long-float simple-array-long-float
+       simple-array-complex-single-float
+       simple-array-complex-double-float
+       #!+long-float simple-array-complex-long-float
+       complex-string
+       complex-bit-vector
+       complex-vector
+       complex-array
+  
+       code-header
+       function-header
+       closure-header
+       funcallable-instance-header
+       byte-code-function
+       byte-code-closure
+       closure-function-header
+       #!-gengc return-pc-header
+       #!+gengc forwarding-pointer
+       value-cell-header
+       symbol-header
+       base-char
+       sap
+       unbound-marker
+       weak-pointer
+       instance-header
+       fdefn
+       #!+(or gengc gencgc) scavenger-hook))
+
+;; Look at the current instruction and see if we can't add some notes
+;; about what's happening.
+
+(defun maybe-add-notes (reg dstate)
+  (let* ((word (sb!disassem::sap-ref-int (sb!disassem::dstate-segment-sap dstate)
+                                     (sb!disassem::dstate-cur-offs dstate)
+                                     n-word-bytes
+                                     (sb!disassem::dstate-byte-order dstate)))
+        (format (ldb (byte 2 30) word))
+        (op3 (ldb (byte 6 19) word))
+        (rs1 (ldb (byte 5 14) word))
+        (rd (ldb (byte 5 25) word))
+        (immed-p (not (zerop (ldb (byte 1 13) word))))
+        (immed-val (sign-extend-immed-value (ldb (byte 13 0) word))))
+    ;; Only the value of format and rd are guaranteed to be correct
+    ;; because the disassembler is trying to print out the value of a
+    ;; register.  The other values may not be right.
+    (case format
+      (2
+       (case op3
+        (#b000000
+         (when (= reg rs1)
+           (handle-add-inst rs1 immed-val rd dstate)))
+        (#b111000
+         (when (= reg rs1)
+           (handle-jmpl-inst rs1 immed-val rd dstate)))
+        (#b010001
+         (when (= reg rs1)
+           (handle-andcc-inst rs1 immed-val rd dstate)))))
+      (3
+       (case op3
+        ((#b000000 #b000100)
+         (when (= reg rs1)
+           (handle-ld/st-inst rs1 immed-val rd dstate))))))
+    ;; If this is not a SETHI instruction, and RD is the same as some
+    ;; register used by SETHI, we delete the entry.  (In case we have
+    ;; a SETHI without any additional instruction because the low bits
+    ;; were zero.)
+    (unless (and (zerop format) (= #b100 (ldb (byte 3 22) word)))
+      (let ((sethi (assoc rd *note-sethi-inst*)))
+       (when sethi
+         (setf *note-sethi-inst* (delete sethi *note-sethi-inst*)))))))
+
+(defun handle-add-inst (rs1 immed-val rd dstate)
+  (let* ((sethi (assoc rs1 *note-sethi-inst*)))
+    (cond
+      (sethi
+       ;; RS1 was used in a SETHI instruction.  Assume that
+       ;; this is the offset part of the SETHI instruction for
+       ;; a full 32-bit address of something.  Make a note
+       ;; about this usage as a Lisp assembly routine or
+       ;; foreign routine, if possible.  If not, just note the
+       ;; final value.
+       (let ((addr (+ immed-val (ash (cdr sethi) 10))))
+        (or (sb!disassem::note-code-constant-absolute addr dstate)
+            (sb!disassem:maybe-note-assembler-routine addr t dstate)
+            (sb!disassem:note (format nil "~A = #x~8,'0X"
+                                    (get-reg-name rd) addr)
+                            dstate)))
+       (setf *note-sethi-inst* (delete sethi *note-sethi-inst*)))
+      ((= rs1 null-offset)
+       ;; We have an ADD %NULL, <n>, RD instruction.  This is a
+       ;; reference to a static symbol.
+       (sb!disassem:maybe-note-nil-indexed-object immed-val
+                                              dstate))
+      ((= rs1 alloc-offset)
+       ;; ADD %ALLOC, n.  This must be some allocation or
+       ;; pseudo-atomic stuff
+       (cond ((and (= immed-val 4) (= rd alloc-offset)
+                  (not *pseudo-atomic-set*))
+             ;; "ADD 4, %ALLOC" sets the flag
+             (sb!disassem::note "Set pseudo-atomic flag" dstate)
+             (setf *pseudo-atomic-set* t))
+            ((= rd alloc-offset)
+             ;; "ADD n, %ALLOC" is reseting the flag, with extra
+             ;; allocation.
+             (sb!disassem:note
+              (format nil "Reset pseudo-atomic, allocated ~D bytes"
+                      (+ immed-val 4)) dstate)
+             (setf *pseudo-atomic-set* nil))))
+      #+nil ((and (= rs1 zero-offset) *pseudo-atomic-set*)
+       ;; "ADD %ZERO, num, RD" inside a pseudo-atomic is very
+       ;; likely loading up a header word.  Make a note to that
+       ;; effect.
+       (let ((type (second (assoc (logand immed-val #xff) header-word-type-alist)))
+            (size (ldb (byte 24 8) immed-val)))
+        (when type
+          (sb!disassem:note (format nil "Header word ~A, size ~D?" type size)
+                         dstate)))))))
+
+(defun handle-jmpl-inst (rs1 immed-val rd dstate)
+  (let* ((sethi (assoc rs1 *note-sethi-inst*)))
+    (when sethi
+      ;; RS1 was used in a SETHI instruction.  Assume that
+      ;; this is the offset part of the SETHI instruction for
+      ;; a full 32-bit address of something.  Make a note
+      ;; about this usage as a Lisp assembly routine or
+      ;; foreign routine, if possible.  If not, just note the
+      ;; final value.
+      (let ((addr (+ immed-val (ash (cdr sethi) 10))))
+       (sb!disassem:maybe-note-assembler-routine addr t dstate)
+       (setf *note-sethi-inst* (delete sethi *note-sethi-inst*))))))
+
+(defun handle-ld/st-inst (rs1 immed-val rd dstate)
+  (declare (ignore rd))
+  ;; Got an LDUW/LD or STW instruction, with immediate offset.
+  (case rs1
+    (29
+     ;; A reference to a code constant (reg = %CODE)
+     (sb!disassem:note-code-constant immed-val dstate))
+    (2
+     ;; A reference to a static symbol or static function (reg =
+     ;; %NULL)
+     (or (sb!disassem:maybe-note-nil-indexed-symbol-slot-ref immed-val
+                                                     dstate)
+        #+nil (sb!disassem::maybe-note-static-function immed-val dstate)))
+    (t
+     (let ((sethi (assoc rs1 *note-sethi-inst*)))
+       (when sethi
+        (let ((addr (+ immed-val (ash (cdr sethi) 10))))
+          (sb!disassem:maybe-note-assembler-routine addr nil dstate)
+          (setf *note-sethi-inst* (delete sethi *note-sethi-inst*))))))))
+
+(defun handle-andcc-inst (rs1 immed-val rd dstate)
+  ;; ANDCC %ALLOC, 3, %ZERO instruction
+  (when (and (= rs1 alloc-offset) (= rd zero-offset) (= immed-val 3))
+    (sb!disassem:note "pseudo-atomic interrupted?" dstate)))
+        
+(sb!disassem:define-arg-type reg
+  :printer (lambda (value stream dstate)
+              (declare (stream stream) (fixnum value))
+              (let ((regname (get-reg-name value)))
+                (princ regname stream)
+                (sb!disassem:maybe-note-associated-storage-ref value
+                                                               'registers
+                                                               regname
+                                                               dstate)
+                (maybe-add-notes value dstate))))
+
+(defparameter float-reg-symbols
+  (coerce 
+   (loop for n from 0 to 63 collect (make-symbol (format nil "%F~d" n)))
+   'vector))
+
+(sb!disassem:define-arg-type fp-reg
+  :printer (lambda (value stream dstate)
+              (declare (stream stream) (fixnum value))
+              (let ((regname (aref float-reg-symbols value)))
+                (princ regname stream)
+                (sb!disassem:maybe-note-associated-storage-ref
+                 value
+                 'float-registers
+                 regname
+                 dstate))))
+
+;;; The extended 6 bit floating point register encoding for the double
+;;; and long instructions of the sparc v9.
+(sb!disassem:define-arg-type fp-ext-reg
+  :printer (lambda (value stream dstate)
+              (declare (stream stream) (fixnum value))
+              (let* (;; Decode the register number.
+                     (value (if (oddp value) (+ value 31) value))
+                     (regname (aref float-reg-symbols value)))
+                (princ regname stream)
+                (sb!disassem:maybe-note-associated-storage-ref
+                 value
+                 'float-registers
+                 regname
+                 dstate))))
+
+(sb!disassem:define-arg-type relative-label
+  :sign-extend t
+  :use-label (lambda (value dstate)
+                (declare (type (signed-byte 13) value)
+                         (type sb!disassem:disassem-state dstate))
+                (+ (ash value 2) (sb!disassem:dstate-cur-addr dstate))))
+
+(defconstant-eqx branch-conditions
+  '(:f :eq :le :lt :leu :ltu :n :vs :t :ne :gt :ge :gtu :geu :p :vc)
+  #'equalp)
+
+;;; Note that these aren't the standard names for branch-conditions, I
+;;; think they're a bit more readable (e.g., "eq" instead of "e").
+;;; You could just put a vector of the normal ones here too.
+
+(sb!disassem:define-arg-type branch-condition
+  :printer (coerce branch-conditions 'vector))
+
+(deftype branch-condition ()
+  `(member ,@branch-conditions))
+
+(defun branch-condition (condition)
+  (or (position condition branch-conditions)
+      (error "Unknown branch condition: ~S~%Must be one of: ~S"
+            condition branch-conditions)))
+
+(defconstant branch-cond-true
+  #b1000)
+
+(defconstant-eqx branch-fp-conditions
+  '(:f :ne :lg :ul :l :ug :g :u :t :eq :ue :ge :uge :le :ule :o)
+  #'equalp)
+
+(sb!disassem:define-arg-type branch-fp-condition
+  :printer (coerce branch-fp-conditions 'vector))
+
+(sb!disassem:define-arg-type call-fixup :use-label t)
+
+(deftype fp-branch-condition ()
+  `(member ,@branch-fp-conditions))
+
+(defun fp-branch-condition (condition)
+  (or (position condition branch-fp-conditions)
+      (error "Unknown fp-branch condition: ~S~%Must be one of: ~S"
+            condition branch-fp-conditions)))
+
+\f
+;;;; dissassem:define-instruction-formats
+
+(sb!disassem:define-instruction-format
+    (format-1 32 :default-printer '(:name :tab disp))
+  (op   :field (byte 2 30) :value 1)
+  (disp :field (byte 30 0)))
+
+(sb!disassem:define-instruction-format
+    (format-2-immed 32 :default-printer '(:name :tab immed ", " rd))
+  (op    :field (byte 2 30) :value 0)
+  (rd    :field (byte 5 25) :type 'reg)
+  (op2   :field (byte 3 22))
+  (immed :field (byte 22 0)))
+
+  
+
+(sb!disassem:define-instruction-format
+    (format-2-branch 32 :default-printer `(:name (:unless (:constant ,branch-cond-true) cond)
+                                          (:unless (a :constant 0) "," 'A)
+                                          :tab
+                                          disp))
+  (op   :field (byte 2 30) :value 0)
+  (a    :field (byte 1 29) :value 0)
+  (cond :field (byte 4 25) :type 'branch-condition)
+  (op2  :field (byte 3 22))
+  (disp :field (byte 22 0) :type 'relative-label))
+
+;; Branch with prediction instruction for V9
+
+;; Currently only %icc and %xcc are used of the four possible values
+
+(defconstant-eqx integer-condition-registers
+  '(:icc :reserved :xcc :reserved)
+  #'equalp)
+
+(defconstant-eqx integer-cond-reg-name-vec
+  (coerce integer-condition-registers 'vector)
+  #'equalp)
+
+(deftype integer-condition-register ()
+  `(member ,@(remove :reserved integer-condition-registers)))
+
+(defparameter integer-condition-reg-symbols
+  (map 'vector
+       (lambda (name)
+          (make-symbol (concatenate 'string "%" (string name))))
+       integer-condition-registers))
+
+(sb!disassem:define-arg-type integer-condition-register
+    :printer (lambda (value stream dstate)
+                (declare (stream stream) (fixnum value) (ignore dstate))
+                (let ((regname (aref integer-condition-reg-symbols value)))
+                  (princ regname stream))))
+
+(defconstant-eqx branch-predictions
+  '(:pn :pt)
+  #'equalp)
+
+(sb!disassem:define-arg-type branch-prediction
+    :printer (coerce branch-predictions 'vector))
+
+(defun integer-condition (condition-reg)
+  (declare (type (member :icc :xcc) condition-reg))
+  (or (position condition-reg integer-condition-registers)
+      (error "Unknown integer condition register:  ~S~%"
+            condition-reg)))
+
+(defun branch-prediction (pred)
+  (or (position pred branch-predictions)
+      (error "Unknown branch prediction:  ~S~%Must be one of: ~S~%"
+            pred branch-predictions)))
+
+(defconstant-eqx branch-pred-printer
+  `(:name (:unless (:constant ,branch-cond-true) cond)
+         (:unless (a :constant 0) "," 'A)
+          (:unless (p :constant 1) "," 'pn)
+         :tab
+         cc
+         ", "
+         disp)
+  #'equalp)
+
+(sb!disassem:define-instruction-format
+    (format-2-branch-pred 32 :default-printer branch-pred-printer)
+  (op   :field (byte 2 30) :value 0)
+  (a    :field (byte 1 29) :value 0)
+  (cond :field (byte 4 25) :type 'branch-condition)
+  (op2  :field (byte 3 22))
+  (cc   :field (byte 2 20) :type 'integer-condition-register)
+  (p    :field (byte 1 19))
+  (disp :field (byte 19 0) :type 'relative-label))
+
+(defconstant-eqx fp-condition-registers
+  '(:fcc0 :fcc1 :fcc2 :fcc3)
+  #'equalp)
+
+(defconstant-eqx fp-cond-reg-name-vec
+  (coerce fp-condition-registers 'vector)
+  #'equalp)
+
+(defparameter fp-condition-reg-symbols
+  (map 'vector
+       (lambda (name)
+          (make-symbol (concatenate 'string "%" (string name))))
+       fp-condition-registers))
+
+(sb!disassem:define-arg-type fp-condition-register
+    :printer (lambda (value stream dstate)
+                (declare (stream stream) (fixnum value) (ignore dstate))
+                (let ((regname (aref fp-condition-reg-symbols value)))
+                  (princ regname stream))))
+
+(sb!disassem:define-arg-type fp-condition-register-shifted
+    :printer (lambda (value stream dstate)
+                (declare (stream stream) (fixnum value) (ignore dstate))
+                (let ((regname (aref fp-condition-reg-symbols (ash value -1))))
+                  (princ regname stream))))
+
+(defun fp-condition (condition-reg)
+  (or (position condition-reg fp-condition-registers)
+      (error "Unknown integer condition register:  ~S~%"
+            condition-reg)))
+
+(defconstant-eqx fp-branch-pred-printer
+  `(:name (:unless (:constant ,branch-cond-true) cond)
+         (:unless (a :constant 0) "," 'A)
+         (:unless (p :constant 1) "," 'pn)
+         :tab
+         fcc
+         ", "
+         disp)
+  #'equalp)
+
+(sb!disassem:define-instruction-format
+    (format-2-fp-branch-pred 32 :default-printer fp-branch-pred-printer)
+  (op   :field (byte 2 30) :value 0)
+  (a    :field (byte 1 29) :value 0)
+  (cond :field (byte 4 25) :type 'branch-fp-condition)
+  (op2  :field (byte 3 22))
+  (fcc  :field (byte 2 20) :type 'fp-condition-register)
+  (p    :field (byte 1 19))
+  (disp :field (byte 19 0) :type 'relative-label))
+  
+
+
+(sb!disassem:define-instruction-format
+    (format-2-unimp 32 :default-printer '(:name :tab data))
+  (op     :field (byte 2 30) :value 0)
+  (ignore :field (byte 5 25) :value 0)
+  (op2    :field (byte 3 22) :value 0)
+  (data   :field (byte 22 0)))
+
+(defconstant-eqx f3-printer
+  '(:name :tab
+         (:unless (:same-as rd) rs1 ", ")
+         (:choose rs2 immed) ", "
+         rd)
+  #'equalp)
+
+(sb!disassem:define-instruction-format
+    (format-3-reg 32 :default-printer f3-printer)
+  (op  :field (byte 2 30))
+  (rd  :field (byte 5 25) :type 'reg)
+  (op3 :field (byte 6 19))
+  (rs1 :field (byte 5 14) :type 'reg)
+  (i   :field (byte 1 13) :value 0)
+  (asi :field (byte 8 5)  :value 0)
+  (rs2 :field (byte 5 0)  :type 'reg))
+
+(sb!disassem:define-instruction-format
+    (format-3-immed 32 :default-printer f3-printer)
+  (op    :field (byte 2 30))
+  (rd    :field (byte 5 25) :type 'reg)
+  (op3   :field (byte 6 19))
+  (rs1   :field (byte 5 14) :type 'reg)
+  (i     :field (byte 1 13) :value 1)
+  (immed :field (byte 13 0) :sign-extend t))   ; usually sign extended
+
+(sb!disassem:define-instruction-format
+    (format-binary-fpop 32
+     :default-printer '(:name :tab rs1 ", " rs2 ", " rd))
+  (op  :field (byte 2 30))
+  (rd  :field (byte 5 25) :type 'fp-reg)
+  (op3  :field (byte 6 19))
+  (rs1  :field (byte 5 14) :type 'fp-reg)
+  (opf  :field (byte 9 5))
+  (rs2  :field (byte 5 0) :type 'fp-reg))
+
+;;; Floating point load/save instructions encoding.
+(sb!disassem:define-instruction-format
+    (format-unary-fpop 32 :default-printer '(:name :tab rs2 ", " rd))
+  (op  :field (byte 2 30))
+  (rd  :field (byte 5 25) :type 'fp-reg)
+  (op3  :field (byte 6 19))
+  (rs1  :field (byte 5 14) :value 0)
+  (opf  :field (byte 9 5))
+  (rs2  :field (byte 5 0) :type 'fp-reg))
+
+;;; Floating point comparison instructions encoding.
+
+;; This is a merge of the instructions for FP comparison and FP
+;; conditional moves available in the Sparc V9.  The main problem is
+;; that the new instructions use part of the opcode space used by the
+;; comparison instructions.  In particular, the OPF field is arranged
+;; as so:
+;;
+;; Bit          1       0
+;;              3       5
+;; FMOVcc      0nn0000xx       %fccn
+;;             1000000xx       %icc
+;;             1100000xx       %xcc
+;; FMOVR       0ccc001yy
+;; FCMP                001010zzz
+;;
+;; So we see that if we break up the OPF field into 4 pieces, opf0,
+;; opf1, opf2, and opf3, we can distinguish between these
+;; instructions. So bit 9 (opf2) can be used to distinguish between
+;; FCMP and the rest.  Also note that the nn field overlaps with the
+;; ccc.  We need to take this into account as well.
+;;
+(sb!disassem:define-instruction-format
+    (format-fpop2 32
+                 :default-printer #!-sparc-v9 '(:name :tab rs1 ", " rs2)
+                                  #!+sparc-v9 '(:name :tab rd ", " rs1 ", " rs2))
+  (op  :field (byte 2 30))
+  (rd  :field (byte 5 25) :value 0)
+  (op3  :field (byte 6 19))
+  (rs1  :field (byte 5 14))
+  (opf0 :field (byte 1 13))
+  (opf1 :field (byte 3 10))
+  (opf2 :field (byte 1 9))
+  (opf3 :field (byte 4 5))
+  (rs2  :field (byte 5 0) :type 'fp-reg))
+
+;;; Shift instructions
+(sb!disassem:define-instruction-format
+    (format-3-shift-reg 32 :default-printer f3-printer)
+  (op  :field (byte 2 30))
+  (rd    :field (byte 5 25) :type 'reg)
+  (op3  :field (byte 6 19))
+  (rs1   :field (byte 5 14) :type 'reg)
+  (i     :field (byte 1 13) :value 0)
+  (x     :field (byte 1 12))
+  (asi   :field (byte 7 5) :value 0)
+  (rs2   :field (byte 5 0) :type 'reg))
+
+(sb!disassem:define-instruction-format
+    (format-3-shift-immed 32 :default-printer f3-printer)
+  (op  :field (byte 2 30))
+  (rd    :field (byte 5 25) :type 'reg)
+  (op3  :field (byte 6 19))
+  (rs1   :field (byte 5 14) :type 'reg)
+  (i     :field (byte 1 13) :value 1)
+  (x     :field (byte 1 12))
+  (immed :field (byte 12 0) :sign-extend nil))
+
+\f
+;;; Conditional moves (only available for Sparc V9 architectures)
+
+;; The names of all of the condition registers on the V9: 4 FP
+;; conditions, the original integer condition register and the new
+;; extended register.  The :reserved register is reserved on the V9.
+
+(defconstant-eqx cond-move-condition-registers
+  '(:fcc0 :fcc1 :fcc2 :fcc3 :icc :reserved :xcc :reserved)
+  #'equalp)
+
+(defconstant-eqx cond-move-cond-reg-name-vec
+  (coerce cond-move-condition-registers 'vector)
+  #'equalp)
+
+(deftype cond-move-condition-register ()
+    `(member ,@(remove :reserved cond-move-condition-registers)))
+
+(defparameter cond-move-condition-reg-symbols
+  (map 'vector
+       (lambda (name)
+          (make-symbol (concatenate 'string "%" (string name))))
+       cond-move-condition-registers))
+
+(sb!disassem:define-arg-type cond-move-condition-register
+    :printer (lambda (value stream dstate)
+                (declare (stream stream) (fixnum value) (ignore dstate))
+                (let ((regname (aref cond-move-condition-reg-symbols value)))
+                  (princ regname stream))))
+
+;; From the given condition register, figure out what the cc2, cc1,
+;; and cc0 bits should be.  Return cc2 and cc1/cc0 concatenated.
+(defun cond-move-condition-parts (condition-reg)
+  (let ((posn (position condition-reg cond-move-condition-registers)))
+    (if posn
+       (truncate posn 4)
+       (error "Unknown conditional move condition register:  ~S~%"
+              condition-reg))))
+
+(defun cond-move-condition (condition-reg)
+  (or (position condition-reg cond-move-condition-registers)
+      (error "Unknown conditional move condition register:  ~S~%")))
+
+(defconstant-eqx cond-move-printer
+  `(:name cond :tab
+          cc ", " (:choose immed rs2) ", " rd)
+  #'equalp)
+
+;; Conditional move integer register on integer or FP condition code
+(sb!disassem:define-instruction-format
+    (format-4-cond-move 32 :default-printer cond-move-printer)
+  (op  :field (byte 2 30))
+  (rd    :field (byte 5 25) :type 'reg)
+  (op3  :field (byte 6 19))
+  (cc2   :field (byte 1 18) :value 1)
+  (cond  :field (byte 4 14) :type 'branch-condition)
+  (i     :field (byte 1 13) :value 0)
+  (cc    :field (byte 2 11) :type 'integer-condition-register)
+  (empty :field (byte 6 5) :value 0)
+  (rs2   :field (byte 5 0) :type 'reg))
+
+(sb!disassem:define-instruction-format
+    (format-4-cond-move-immed 32 :default-printer cond-move-printer)
+  (op    :field (byte 2 30))
+  (rd    :field (byte 5 25) :type 'reg)
+  (op3   :field (byte 6 19))
+  (cc2   :field (byte 1 18) :value 1)
+  (cond  :field (byte 4 14) :type 'branch-condition)
+  (i     :field (byte 1 13) :value 1)
+  (cc    :field (byte 2 11) :type 'integer-condition-register)
+  (immed :field (byte 11 0) :sign-extend t))
+
+;; Floating-point versions of the above integer conditional moves
+(defconstant-eqx cond-fp-move-printer
+  `(:name rs1 :tab opf1 ", " rs2 ", " rd)
+  #'equalp)
+
+;;; Conditional move on integer register condition (only on Sparc
+;;; V9). That is, move an integer register if some other integer
+;;; register satisfies some condition.
+
+(defconstant-eqx cond-move-integer-conditions
+  '(:reserved :z :lez :lz :reserved :nz :gz :gez)
+  #'equalp)
+
+(defconstant-eqx cond-move-integer-condition-vec
+  (coerce cond-move-integer-conditions 'vector)
+  #'equalp)
+
+(deftype cond-move-integer-condition ()
+  `(member ,@(remove :reserved cond-move-integer-conditions)))
+
+(sb!disassem:define-arg-type register-condition
+    :printer (lambda (value stream dstate)
+                (declare (stream stream) (fixnum value) (ignore dstate))
+                (let ((regname (aref cond-move-integer-condition-vec value)))
+                  (princ regname stream))))
+
+(defconstant-eqx cond-move-integer-printer
+  `(:name rcond :tab rs1 ", " (:choose immed rs2) ", " rd)
+  #'equalp)
+
+(defun register-condition (rcond)
+  (or (position rcond cond-move-integer-conditions)
+      (error "Unknown register condition:  ~S~%")))
+
+(sb!disassem:define-instruction-format
+    (format-4-cond-move-integer 32 :default-printer cond-move-integer-printer)
+  (op    :field (byte 2 30))
+  (rd    :field (byte 5 25) :type 'reg)
+  (op3   :field (byte 6 19))
+  (rs1   :field (byte 5 14) :type 'reg)
+  (i     :field (byte 1 13) :value 0)
+  (rcond :field (byte 3 10) :type 'register-condition)
+  (opf   :field (byte 5 5))
+  (rs2   :field (byte 5 0) :type 'reg))
+
+(sb!disassem:define-instruction-format
+    (format-4-cond-move-integer-immed 32 :default-printer cond-move-integer-printer)
+  (op    :field (byte 2 30))
+  (rd    :field (byte 5 25) :type 'reg)
+  (op3   :field (byte 6 19))
+  (rs1   :field (byte 5 14) :type 'reg)
+  (i     :field (byte 1 13) :value 1)
+  (rcond :field (byte 3 10) :type 'register-condition)
+  (immed :field (byte 10 0) :sign-extend t))
+
+(defconstant-eqx trap-printer
+  `(:name rd :tab cc ", " immed)
+  #'equalp)
+
+(sb!disassem:define-instruction-format
+    (format-4-trap 32 :default-printer trap-printer)
+  (op    :field (byte 2 30))
+  (rd    :field (byte 5 25) :type 'reg)
+  (op3   :field (byte 6 19))
+  (rs1   :field (byte 5 14) :type 'reg)
+  (i     :field (byte 1 13) :value 1)
+  (cc    :field (byte 2 11) :type 'integer-condition-register)
+  (immed :field (byte 11 0) :sign-extend t))   ; usually sign extended
+
+
+(defconstant-eqx cond-fp-move-integer-printer
+  `(:name opf1 :tab rs1 ", " rs2 ", " rd)
+  #'equalp)
+
+\f
+;;;; Primitive emitters.
+
+(define-bitfield-emitter emit-word 32
+  (byte 32 0))
+
+(define-bitfield-emitter emit-short 16
+  (byte 16 0))
+
+(define-bitfield-emitter emit-format-1 32
+  (byte 2 30) (byte 30 0))
+
+(define-bitfield-emitter emit-format-2-immed 32
+  (byte 2 30) (byte 5 25) (byte 3 22) (byte 22 0))
+
+(define-bitfield-emitter emit-format-2-branch 32
+  (byte 2 30) (byte 1 29) (byte 4 25) (byte 3 22) (byte 22 0))
+
+;; Integer and FP branches with prediction for V9
+(define-bitfield-emitter emit-format-2-branch-pred 32
+  (byte 2 30) (byte 1 29) (byte 4 25) (byte 3 22) (byte 2 20) (byte 1 19) (byte 19 0))
+(define-bitfield-emitter emit-format-2-fp-branch-pred 32
+  (byte 2 30) (byte 1 29) (byte 4 25) (byte 3 22) (byte 2 20) (byte 1 19) (byte 19 0))
+  
+(define-bitfield-emitter emit-format-2-unimp 32
+  (byte 2 30) (byte 5 25) (byte 3 22) (byte 22 0))
+
+(define-bitfield-emitter emit-format-3-reg 32
+  (byte 2 30) (byte 5 25) (byte 6 19) (byte 5 14) (byte 1 13) (byte 8 5)
+  (byte 5 0))
+
+(define-bitfield-emitter emit-format-3-immed 32
+  (byte 2 30) (byte 5 25) (byte 6 19) (byte 5 14) (byte 1 13) (byte 13 0))
+
+(define-bitfield-emitter emit-format-3-fpop 32
+  (byte 2 30) (byte 5 25) (byte 6 19) (byte 5 14) (byte 9 5) (byte 5 0))
+
+(define-bitfield-emitter emit-format-3-fpop2 32
+  (byte 2 30) (byte 5 25) (byte 6 19) (byte 5 14)
+  (byte 1 13) (byte 3 10) (byte 1 9) (byte 4 5)
+  (byte 5 0))
+
+;;; Shift instructions
+
+(define-bitfield-emitter emit-format-3-shift-reg 32
+  (byte 2 30) (byte 5 25) (byte 6 19) (byte 5 14) (byte 1 13) (byte 1 12) (byte 7 5)
+  (byte 5 0))
+
+(define-bitfield-emitter emit-format-3-shift-immed 32
+  (byte 2 30) (byte 5 25) (byte 6 19) (byte 5 14) (byte 1 13) (byte 1 12) (byte 12 0))
+
+;;; Conditional moves
+
+;; Conditional move in condition code
+(define-bitfield-emitter emit-format-4-cond-move 32
+  (byte 2 30) (byte 5 25) (byte 6 19) (byte 1 18) (byte 4 14) (byte 1 13) (byte 2 11)
+  (byte 11 0))
+
+;; Conditional move on integer condition
+(define-bitfield-emitter emit-format-4-cond-move-integer 32
+  (byte 2 30) (byte 5 25) (byte 6 19) (byte 5 14) (byte 1 13) (byte 3 10) (byte 5 5)
+  (byte 5 0))
+
+(define-bitfield-emitter emit-format-4-cond-move-integer-immed 32
+  (byte 2 30) (byte 5 25) (byte 6 19) (byte 5 14) (byte 1 13) (byte 3 10)
+  (byte 10 0))
+
+(define-bitfield-emitter emit-format-4-trap 32
+  (byte 2 30) (byte 5 25) (byte 6 19) (byte 5 14) (byte 1 13) (byte 2 11)
+  (byte 11 0))
+  
+\f
+;;;; Most of the format-3-instructions.
+
+(defun emit-format-3-inst (segment op op3 dst src1 src2
+                                  &key load-store fixup dest-kind)
+  (unless src2
+    (cond ((and (typep src1 'tn) load-store)
+          (setf src2 0))
+         (t
+          (setf src2 src1)
+          (setf src1 dst))))
+  (etypecase src2
+    (tn
+     (emit-format-3-reg segment op
+                       (if dest-kind
+                           (fp-reg-tn-encoding dst)
+                           (reg-tn-encoding dst))
+                       op3 (reg-tn-encoding src1) 0 0 (reg-tn-encoding src2)))
+    (integer
+     (emit-format-3-immed segment op
+                         (if dest-kind
+                             (fp-reg-tn-encoding dst)
+                             (reg-tn-encoding dst))
+                         op3 (reg-tn-encoding src1) 1 src2))
+    (fixup
+     (unless (or load-store fixup)
+       (error "Fixups aren't allowed."))
+     (note-fixup segment :add src2)
+     (emit-format-3-immed segment op
+                         (if dest-kind
+                             (fp-reg-tn-encoding dst)
+                             (reg-tn-encoding dst))
+                         op3 (reg-tn-encoding src1) 1 0))))
+
+;;; Shift instructions because an extra bit is used in Sparc V9's to
+;;; indicate whether the shift is a 32-bit or 64-bit shift.
+;;;
+(defun emit-format-3-shift-inst (segment op op3 dst src1 src2 &key extended)
+  (unless src2
+    (setf src2 src1)
+    (setf src1 dst))
+  (etypecase src2
+    (tn
+     (emit-format-3-shift-reg segment op (reg-tn-encoding dst)
+                             op3 (reg-tn-encoding src1) 0 (if extended 1 0)
+                             0 (reg-tn-encoding src2)))
+    (integer
+     (emit-format-3-shift-immed segment op (reg-tn-encoding dst)
+                               op3 (reg-tn-encoding src1) 1
+                               (if extended 1 0) src2))))
+
+
+(eval-when (:compile-toplevel :execute)
+
+;;; have to do this because defconstant is evalutated in the null lex env.
+(defmacro with-ref-format (printer)
+  `(let* ((addend
+          '(:choose (:plus-integer immed) ("+" rs2)))
+         (ref-format
+          `("[" rs1 (:unless (:constant 0) ,addend) "]"
+            (:choose (:unless (:constant 0) asi) nil))))
+     ,printer))
+
+(defconstant-eqx load-printer
+  (with-ref-format `(:NAME :TAB ,ref-format ", " rd))
+  #'equalp)
+
+(defconstant-eqx store-printer
+  (with-ref-format `(:NAME :TAB rd ", " ,ref-format))
+  #'equalp)
+
+) ; eval-when (compile eval)
+
+(macrolet ((define-f3-inst (name op op3 &key fixup load-store (dest-kind 'reg)
+                                (printer :default) reads writes flushable print-name)
+  (let ((printer
+        (if (eq printer :default)
+            (case load-store
+              ((nil) :default)
+              ((:load t) 'load-printer)
+              (:store 'store-printer))
+            printer)))
+    (when (and (atom reads) (not (null reads)))
+      (setf reads (list reads)))
+    (when (and (atom writes) (not (null writes)))
+       (setf writes (list writes)))
+    `(define-instruction ,name (segment dst src1 &optional src2)
+       (:declare (type tn dst)
+                ,(if (or fixup load-store)
+                     '(type (or tn (signed-byte 13) null fixup) src1 src2)
+                     '(type (or tn (signed-byte 13) null) src1 src2)))
+       (:printer format-3-reg
+                ((op ,op) (op3 ,op3) (rd nil :type ',dest-kind))
+                ,printer
+                ,@(when print-name `(:print-name ,print-name)))
+       (:printer format-3-immed
+                ((op ,op) (op3 ,op3) (rd nil :type ',dest-kind))
+                ,printer
+                ,@(when print-name `(:print-name ,print-name)))
+       ,@(when flushable
+          '((:attributes flushable)))
+       (:dependencies
+       (reads src1)
+       ,@(let ((reads-list nil))
+           (dolist (read reads)
+             (push (list 'reads read) reads-list))
+           reads-list)
+       ,@(cond ((eq load-store :store)
+                '((reads dst)
+                  (if src2 (reads src2))))
+                ((eq load-store t)
+                 '((reads :memory)
+                   (reads dst)
+                   (if src2 (reads src2))))
+               ((eq load-store :load)
+                '((reads :memory)
+                  (if src2 (reads src2) (reads dst))))
+               (t
+                '((if src2 (reads src2) (reads dst)))))
+       ,@(let ((writes-list nil))
+           (dolist (write writes)
+             (push (list 'writes write) writes-list))
+           writes-list)
+       ,@(cond ((eq load-store :store)
+                '((writes :memory :partially t)))
+               ((eq load-store t)
+                '((writes :memory :partially t)
+                  (writes dst)))
+               ((eq load-store :load)
+                '((writes dst)))
+               (t
+                '((writes dst)))))
+       (:delay 0)
+       (:emitter (emit-format-3-inst segment ,op ,op3 dst src1 src2
+                                    :load-store ,load-store
+                                    :fixup ,fixup
+                                    :dest-kind (not (eq ',dest-kind 'reg)))))))
+
+          (define-f3-shift-inst (name op op3 &key extended)
+              `(define-instruction ,name (segment dst src1 &optional src2)
+                (:declare (type tn dst)
+                 (type (or tn (unsigned-byte 6) null) src1 src2))
+                (:printer format-3-shift-reg
+                 ((op ,op) (op3 ,op3) (x ,(if extended 1 0)) (i 0)))
+                (:printer format-3-shift-immed
+                 ((op ,op) (op3 ,op3) (x ,(if extended 1 0)) (i 1)))
+                (:dependencies
+                 (reads src1)
+                 (if src2 (reads src2) (reads dst))
+                 (writes dst))
+                (:delay 0)
+                (:emitter (emit-format-3-shift-inst segment ,op ,op3 dst src1 src2
+                           :extended ,extended)))))
+
+  (define-f3-inst ldsb #b11 #b001001 :load-store :load)
+  (define-f3-inst ldsh #b11 #b001010 :load-store :load)
+  (define-f3-inst ldub #b11 #b000001 :load-store :load)
+  (define-f3-inst lduh #b11 #b000010 :load-store :load)
+
+  ;; This instruction is called lduw for V9 , but looks exactly like ld
+  ;; on previous architectures.
+  (define-f3-inst ld #b11 #b000000 :load-store :load
+                 #!+sparc-v9 :print-name #!+sparc-v9 'lduw)
+
+  (define-f3-inst ldsw #b11 #b001000 :load-store :load) ; v9
+  
+  ;; ldd is deprecated on the Sparc V9.
+  (define-f3-inst ldd #b11 #b000011 :load-store :load)
+  
+  (define-f3-inst ldx #b11 #b001011 :load-store :load) ; v9
+  
+  (define-f3-inst ldf #b11 #b100000 :dest-kind fp-reg :load-store :load)
+  (define-f3-inst lddf #b11 #b100011 :dest-kind fp-reg :load-store :load)
+  (define-f3-inst ldqf #b11 #b100010 :dest-kind fp-reg :load-store :load)      ; v9
+  (define-f3-inst stb #b11 #b000101 :load-store :store)
+  (define-f3-inst sth #b11 #b000110 :load-store :store)
+  (define-f3-inst st #b11 #b000100 :load-store :store)
+  
+  ;; std is deprecated on the Sparc V9.
+  (define-f3-inst std #b11 #b000111 :load-store :store)
+  
+  (define-f3-inst stx #b11 #b001110 :load-store :store) ; v9
+  
+  (define-f3-inst stf #b11 #b100100 :dest-kind fp-reg :load-store :store)
+  (define-f3-inst stdf #b11 #b100111 :dest-kind fp-reg :load-store :store)
+  (define-f3-inst stqf #b11 #b100110 :dest-kind fp-reg :load-store :store) ; v9
+  (define-f3-inst ldstub #b11 #b001101 :load-store t)
+  
+  ;; swap is deprecated on the Sparc V9
+  (define-f3-inst swap #b11 #b001111 :load-store t)
+  
+  (define-f3-inst add #b10 #b000000 :fixup t)
+  (define-f3-inst addcc #b10 #b010000 :writes :psr)
+  (define-f3-inst addx #b10 #b001000 :reads :psr)
+  (define-f3-inst addxcc #b10 #b011000 :reads :psr :writes :psr)
+  (define-f3-inst taddcc #b10 #b100000 :writes :psr)
+  
+  ;; taddcctv is deprecated on the Sparc V9.  Use taddcc and bpvs or
+  ;; taddcc and trap to get a similar effect.  (Requires changing the C
+  ;; code though!)
+  ;;(define-f3-inst taddcctv #b10 #b100010 :writes :psr)
+
+  (define-f3-inst sub #b10 #b000100)
+  (define-f3-inst subcc #b10 #b010100 :writes :psr)
+  (define-f3-inst subx #b10 #b001100 :reads :psr)
+  (define-f3-inst subxcc #b10 #b011100 :reads :psr :writes :psr)
+  (define-f3-inst tsubcc #b10 #b100001 :writes :psr)
+
+  ;; tsubcctv is deprecated on the Sparc V9.  Use tsubcc and bpvs or
+  ;; tsubcc and trap to get a similar effect.  (Requires changing the C
+  ;; code though!)
+  ;;(define-f3-inst tsubcctv #b10 #b100011 :writes :psr)
+
+  (define-f3-inst mulscc #b10 #b100100 :reads :y :writes (:psr :y))
+  (define-f3-inst and #b10 #b000001)
+  (define-f3-inst andcc #b10 #b010001 :writes :psr)
+  (define-f3-inst andn #b10 #b000101)
+  (define-f3-inst andncc #b10 #b010101 :writes :psr)
+  (define-f3-inst or #b10 #b000010)
+  (define-f3-inst orcc #b10 #b010010 :writes :psr)
+  (define-f3-inst orn #b10 #b000110)
+  (define-f3-inst orncc #b10 #b010110 :writes :psr)
+  (define-f3-inst xor #b10 #b000011)
+  (define-f3-inst xorcc #b10 #b010011 :writes :psr)
+  (define-f3-inst xnor #b10 #b000111)
+  (define-f3-inst xnorcc #b10 #b010111 :writes :psr)
+  
+  (define-f3-shift-inst sll #b10 #b100101)
+  (define-f3-shift-inst srl #b10 #b100110)
+  (define-f3-shift-inst sra #b10 #b100111)
+  (define-f3-shift-inst sllx #b10 #b100101 :extended t)        ; v9
+  (define-f3-shift-inst srlx #b10 #b100110 :extended t)        ; v9
+  (define-f3-shift-inst srax #b10 #b100111 :extended t)        ; v9
+
+  (define-f3-inst save #b10 #b111100 :reads :psr :writes :psr)
+  (define-f3-inst restore #b10 #b111101 :reads :psr :writes :psr)
+  
+  ;; smul, smulcc, umul, umulcc, sdiv, sdivcc, udiv, and udivcc are
+  ;; deprecated on the Sparc V9.  Use mulx, sdivx, and udivx instead.
+  (define-f3-inst smul #b10 #b001011 :writes :y)                       ; v8
+  (define-f3-inst smulcc #b10 #b011011 :writes (:psr :y))              ; v8
+  (define-f3-inst umul #b10 #b001010 :writes :y)                       ; v8
+  (define-f3-inst umulcc #b10 #b011010 :writes (:psr :y))              ; v8
+  (define-f3-inst sdiv #b10 #b001111 :reads :y)                        ; v8
+  (define-f3-inst sdivcc #b10 #b011111 :reads :y :writes :psr) ; v8
+  (define-f3-inst udiv #b10 #b001110 :reads :y)                        ; v8
+  (define-f3-inst udivcc #b10 #b011110 :reads :y :writes :psr) ; v8
+  
+  (define-f3-inst mulx #b10 #b001001)  ; v9 for both signed and unsigned
+  (define-f3-inst sdivx #b10 #b101101) ; v9
+  (define-f3-inst udivx #b10 #b001101) ; v9
+
+  (define-f3-inst popc #b10 #b101110)  ; v9: count one bits
+
+) ; MACROLET
+
+\f
+;;;; Random instructions.
+
+;; ldfsr is deprecated on the Sparc V9.  Use ldxfsr instead
+(define-instruction ldfsr (segment src1 src2)
+  (:declare (type tn src1) (type (signed-byte 13) src2))
+  (:printer format-3-immed ((op #b11) (op3 #b100001) (rd 0)))
+  :pinned
+  (:delay 0)
+  (:emitter (emit-format-3-immed segment #b11 0 #b100001
+                                (reg-tn-encoding src1) 1 src2)))
+
+#!+sparc-64
+(define-instruction ldxfsr (segment src1 src2)
+  (:declare (type tn src1) (type (signed-byte 13) src2))
+  (:printer format-3-immed ((op #b11) (op3 #b100001) (rd 1))
+           '(:name :tab "[" rs1 (:unless (:constant 0) "+" immed) "], %FSR")
+           :print-name 'ldx)
+  :pinned
+  (:delay 0)
+  (:emitter (emit-format-3-immed segment #b11 1 #b100001
+                                (reg-tn-encoding src1) 1 src2)))
+  
+;; stfsr is deprecated on the Sparc V9.  Use stxfsr instead.
+(define-instruction stfsr (segment src1 src2)
+  (:declare (type tn src1) (type (signed-byte 13) src2))
+  (:printer format-3-immed ((op #b11) (op3 #b100101) (rd 0)))
+  :pinned
+  (:delay 0)
+  (:emitter (emit-format-3-immed segment #b11 0 #b100101 
+                                (reg-tn-encoding src1) 1 src2)))
+
+#!+sparc-64
+(define-instruction stxfsr (segment src1 src2)
+  (:declare (type tn src1) (type (signed-byte 13) src2))
+  (:printer format-3-immed ((op #b11) (op3 #b100101) (rd 1))
+           '(:name :tab "%FSR, [" rs1 "+" (:unless (:constant 0) "+" immed) "]")
+           :print-name 'stx)
+  :pinned
+  (:delay 0)
+  (:emitter (emit-format-3-immed segment #b11 1 #b100101 
+                                (reg-tn-encoding src1) 1 src2)))
+
+(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute)
+  (defun sethi-arg-printer (value stream dstate)
+    (format stream "%hi(#x~8,'0x)" (ash value 10))
+    ;; Save the immediate value and the destination register from this
+    ;; sethi instruction.  This is used later to print some possible
+    ;; notes about the value loaded by sethi.
+    (let* ((word (sb!disassem::sap-ref-int (sb!disassem::dstate-segment-sap dstate)
+                                          (sb!disassem::dstate-cur-offs dstate)
+                                          n-word-bytes
+                                          (sb!disassem::dstate-byte-order dstate)))
+          (imm22 (ldb (byte 22 0) word))
+          (rd (ldb (byte 5 25) word)))
+      (push (cons rd imm22) *note-sethi-inst*)))
+) ; EVAL-WHEN
+
+
+(define-instruction sethi (segment dst src1)
+  (:declare (type tn dst)
+           (type (or (signed-byte 22) (unsigned-byte 22) fixup) src1))
+  (:printer format-2-immed
+            ((op2 #b100) (immed nil :printer #'sethi-arg-printer)))
+  (:dependencies (writes dst))
+  (:delay 0)
+  (:emitter
+   (etypecase src1
+     (integer
+      (emit-format-2-immed segment #b00 (reg-tn-encoding dst) #b100
+                                src1))
+     (fixup
+      (note-fixup segment :sethi src1)
+      (emit-format-2-immed segment #b00 (reg-tn-encoding dst) #b100 0)))))
+                          
+;; rdy is deprecated on the Sparc V9.  It's not needed with 64-bit
+;; registers.
+(define-instruction rdy (segment dst)
+  (:declare (type tn dst))
+  (:printer format-3-immed ((op #b10) (op3 #b101000) (rs1 0) (immed 0))
+            '('RD :tab '%Y ", " rd))
+  (:dependencies (reads :y) (writes dst))
+  (:delay 0)
+  (:emitter (emit-format-3-immed segment #b10 (reg-tn-encoding dst) #b101000
+                                0 0 0)))
+
+(defconstant-eqx wry-printer
+  '('WR :tab rs1 (:unless (:constant 0) ", " (:choose immed rs2)) ", " '%Y)
+  #'equalp)
+
+;; wry is deprecated on the Sparc V9.  It's not needed with 64-bit
+;; registers.
+(define-instruction wry (segment src1 &optional src2)
+  (:declare (type tn src1) (type (or (signed-byte 13) tn null) src2))
+  (:printer format-3-reg ((op #b10) (op3 #b110000) (rd 0)) wry-printer)
+  (:printer format-3-immed ((op #b10) (op3 #b110000) (rd 0)) wry-printer)
+  (:dependencies (reads src1) (if src2 (reads src2)) (writes :y))
+  (:delay 3)
+  (:emitter
+   (etypecase src2
+     (null 
+      (emit-format-3-reg segment #b10 0 #b110000 (reg-tn-encoding src1) 0 0 0))
+     (tn
+      (emit-format-3-reg segment #b10 0 #b110000 (reg-tn-encoding src1) 0 0
+                        (reg-tn-encoding src2)))
+     (integer
+      (emit-format-3-immed segment #b10 0 #b110000 (reg-tn-encoding src1) 1
+                          src2)))))
+
+(defun snarf-error-junk (sap offset &optional length-only)
+  (let* ((length (sb!sys:sap-ref-8 sap offset))
+         (vector (make-array length :element-type '(unsigned-byte 8))))
+    (declare (type sb!sys:system-area-pointer sap)
+             (type (unsigned-byte 8) length)
+             (type (simple-array (unsigned-byte 8) (*)) vector))
+    (cond (length-only
+           (values 0 (1+ length) nil nil))
+          (t
+           (sb!kernel:copy-from-system-area sap (* n-byte-bits (1+ offset))
+                                         vector (* n-word-bits
+                                                   vector-data-offset)
+                                         (* length n-byte-bits))
+           (collect ((sc-offsets)
+                     (lengths))
+             (lengths 1)                ; the length byte
+             (let* ((index 0)
+                    (error-number (sb!c:read-var-integer vector index)))
+               (lengths index)
+               (loop
+                 (when (>= index length)
+                   (return))
+                 (let ((old-index index))
+                   (sc-offsets (sb!c:read-var-integer vector index))
+                   (lengths (- index old-index))))
+               (values error-number
+                       (1+ length)
+                       (sc-offsets)
+                       (lengths))))))))
+
+(defun unimp-control (chunk inst stream dstate)
+  (declare (ignore inst))
+  (flet ((nt (x) (if stream (sb!disassem:note x dstate))))
+    (case (format-2-unimp-data chunk dstate)
+      (#.error-trap
+       (nt "Error trap")
+       (sb!disassem:handle-break-args #'snarf-error-junk stream dstate))
+      (#.cerror-trap
+       (nt "Cerror trap")
+       (sb!disassem:handle-break-args #'snarf-error-junk stream dstate))
+      (#.object-not-list-trap
+       (nt "Object not list trap"))
+      (#.breakpoint-trap
+       (nt "Breakpoint trap"))
+      (#.pending-interrupt-trap
+       (nt "Pending interrupt trap"))
+      (#.halt-trap
+       (nt "Halt trap"))
+      (#.fun-end-breakpoint-trap
+       (nt "Function end breakpoint trap"))
+      (#.object-not-instance-trap
+       (nt "Object not instance trap"))
+    )))
+
+(define-instruction unimp (segment data)
+  (:declare (type (unsigned-byte 22) data))
+  (:printer format-2-unimp () :default :control #'unimp-control
+           :print-name #!-sparc-v9 'unimp #!+sparc-v9 'illtrap)
+  (:delay 0)
+  (:emitter (emit-format-2-unimp segment 0 0 0 data)))
+
+
+\f
+;;;; Branch instructions.
+
+;; The branch instruction is deprecated on the Sparc V9.  Use the
+;; branch with prediction instructions instead.
+(defun emit-relative-branch (segment a op2 cond-or-target target &optional fp)
+  (emit-back-patch segment 4
+    (lambda (segment posn)
+       (unless target
+         (setf target cond-or-target)
+         (setf cond-or-target :t))
+       (emit-format-2-branch
+         segment #b00 a
+         (if fp
+             (fp-branch-condition cond-or-target)
+             (branch-condition cond-or-target))
+         op2
+         (let ((offset (ash (- (label-position target) posn) -2)))
+           (when (and (= a 1) (> 0 offset))
+             (error "Offset of BA must be positive"))
+           offset)))))
+
+#!+sparc-v9
+(defun emit-relative-branch-integer (segment a op2 cond-or-target target &optional (cc :icc) (pred :pt))
+  (declare (type integer-condition-register cc))
+  (emit-back-patch segment 4
+    (lambda (segment posn)
+       (unless target
+         (setf target cond-or-target)
+         (setf cond-or-target :t))
+       (emit-format-2-branch-pred
+         segment #b00 a
+         (branch-condition cond-or-target)
+         op2
+         (integer-condition cc)
+         (branch-prediction pred)
+         (let ((offset (ash (- (label-position target) posn) -2)))
+           (when (and (= a 1) (> 0 offset))
+             (error "Offset of BA must be positive"))
+           offset)))))
+
+#!+sparc-v9
+(defun emit-relative-branch-fp (segment a op2 cond-or-target target &optional (cc :fcc0) (pred :pt))
+  (emit-back-patch segment 4
+    (lambda (segment posn)
+       (unless target
+         (setf target cond-or-target)
+         (setf cond-or-target :t))
+       (emit-format-2-branch-pred
+         segment #b00 a
+         (fp-branch-condition cond-or-target)
+         op2
+         (fp-condition cc)
+         (branch-prediction pred)
+         (let ((offset (ash (- (label-position target) posn) -2)))
+           (when (and (= a 1) (> 0 offset))
+             (error "Offset of BA must be positive"))
+           offset)))))
+
+;; So that I don't have to go change the syntax of every single use of
+;; branches, I'm keeping the Lisp instruction names the same.  They
+;; just get translated to the branch with prediction
+;; instructions. However, the disassembler uses the correct V9
+;; mnemonic.
+#!-sparc-v9
+(define-instruction b (segment cond-or-target &optional target)
+  (:declare (type (or label branch-condition) cond-or-target)
+           (type (or label null) target))
+  (:printer format-2-branch ((op #b00) (op2 #b010)))
+  (:attributes branch)
+  (:dependencies (reads :psr))
+  (:delay 1)
+  (:emitter
+   (emit-relative-branch segment 0 #b010 cond-or-target target)))
+
+#!+sparc-v9
+(define-instruction b (segment cond-or-target &optional target pred cc)
+  (:declare (type (or label branch-condition) cond-or-target)
+           (type (or label null) target))
+  (:printer format-2-branch-pred ((op #b00) (op2 #b001))
+           branch-pred-printer
+           :print-name 'bp)
+  (:attributes branch)
+  (:dependencies (reads :psr))
+  (:delay 1)
+  (:emitter
+   (emit-relative-branch-integer segment 0 #b001 cond-or-target target (or cc :icc) (or pred :pt))))
+
+#!-sparc-v9
+(define-instruction ba (segment cond-or-target &optional target)
+  (:declare (type (or label branch-condition) cond-or-target)
+           (type (or label null) target))
+  (:printer format-2-branch ((op #b00) (op2 #b010) (a 1))
+            nil
+            :print-name 'b)
+  (:attributes branch)
+  (:dependencies (reads :psr))
+  (:delay 0)
+  (:emitter
+   (emit-relative-branch segment 1 #b010 cond-or-target target)))
+
+#!+sparc-v9
+(define-instruction ba (segment cond-or-target &optional target pred cc)
+  (:declare (type (or label branch-condition) cond-or-target)
+           (type (or label null) target))
+  (:printer format-2-branch ((op #b00) (op2 #b001) (a 1))
+            nil
+            :print-name 'bp)
+  (:attributes branch)
+  (:dependencies (reads :psr))
+  (:delay 0)
+  (:emitter
+   (emit-relative-branch-integer segment 1 #b001 cond-or-target target (or cc :icc) (or pred :pt))))
+
+;; This doesn't cover all of the possible formats for the trap
+;; instruction.  We really only want a trap with a immediate trap
+;; value and with RS1 = register 0.  Also, the Sparc Compliance
+;; Definition 2.4.1 says only trap numbers 16-31 are allowed for user
+;; code.  All other trap numbers have other uses.  The restriction on
+;; target will prevent us from using bad trap numbers by mistake.
+#!-sparc-v9
+(define-instruction t (segment condition target)
+  (:declare (type branch-condition condition)
+           ;; KLUDGE
+           #!-linux
+           (type (integer 16 31) target))
+  (:printer format-3-immed ((op #b10)
+                            (rd nil :type 'branch-condition)
+                            (op3 #b111010)
+                            (rs1 0))
+            '(:name rd :tab immed))
+  (:attributes branch)
+  (:dependencies (reads :psr))
+  (:delay 0)
+  (:emitter (emit-format-3-immed segment #b10 (branch-condition condition)
+                                #b111010 0 1 target)))
+
+#!+sparc-v9
+(define-instruction t (segment condition target &optional (cc #!-sparc-64 :icc #!+sparc-64 :xcc))
+  (:declare (type branch-condition condition)
+           #!-linux
+           (type (integer 16 31) target)
+           (type integer-condition-register cc))
+  (:printer format-4-trap ((op #b10)
+                            (rd nil :type 'branch-condition)
+                            (op3 #b111010)
+                            (rs1 0))
+            trap-printer)
+  (:attributes branch)
+  (:dependencies (reads :psr))
+  (:delay 0)
+  (:emitter (emit-format-4-trap segment
+                               #b10
+                               (branch-condition condition)
+                               #b111010 0 1
+                               (integer-condition cc)
+                               target)))
+
+;; Same as for the branch instructions.  On the Sparc V9, we will use
+;; the FP branch with prediction instructions instead.
+#!-sparc-v9
+(define-instruction fb (segment condition target)
+  (:declare (type fp-branch-condition condition) (type label target))
+  (:printer format-2-branch ((op #B00)
+                             (cond nil :type 'branch-fp-condition)
+                             (op2 #b110)))
+  (:attributes branch)
+  (:dependencies (reads :fsr))
+  (:delay 1)
+  (:emitter
+   (emit-relative-branch segment 0 #b110 condition target t)))
+
+#!+sparc-v9
+(define-instruction fb (segment condition target &optional fcc pred)
+  (:declare (type fp-branch-condition condition) (type label target))
+  (:printer format-2-fp-branch-pred ((op #b00) (op2 #b101))
+           fp-branch-pred-printer
+           :print-name 'fbp)
+  (:attributes branch)
+  (:dependencies (reads :fsr))
+  (:delay 1)
+  (:emitter
+   (emit-relative-branch-fp segment 0 #b101 condition target (or fcc :fcc0) (or pred :pt))))
+
+(defconstant-eqx jal-printer
+  '(:name :tab
+          (:choose (rs1 (:unless (:constant 0) (:plus-integer immed)))
+                   (:cond ((rs2 :constant 0) rs1)
+                          ((rs1 :constant 0) rs2)
+                          (t rs1 "+" rs2)))
+          (:unless (:constant 0) ", " rd))
+  #'equalp)
+
+(define-instruction jal (segment dst src1 &optional src2)
+  (:declare (type tn dst)
+           (type (or tn integer) src1)
+           (type (or null fixup tn (signed-byte 13)) src2))
+  (:printer format-3-reg ((op #b10) (op3 #b111000)) jal-printer)
+  (:printer format-3-immed ((op #b10) (op3 #b111000)) jal-printer)
+  (:attributes branch)
+  (:dependencies (reads src1) (if src2 (reads src2) (reads dst)) (writes dst))
+  (:delay 1)
+  (:emitter
+   (unless src2
+     (setf src2 src1)
+     (setf src1 0))
+   (etypecase src2
+     (tn
+      (emit-format-3-reg segment #b10 (reg-tn-encoding dst) #b111000
+                        (if (integerp src1)
+                            src1
+                            (reg-tn-encoding src1))
+                        0 0 (reg-tn-encoding src2)))
+     (integer
+      (emit-format-3-immed segment #b10 (reg-tn-encoding dst) #b111000
+                          (reg-tn-encoding src1) 1 src2))
+     (fixup
+      (note-fixup segment :add src2)
+      (emit-format-3-immed segment #b10 (reg-tn-encoding dst)
+                          #b111000 (reg-tn-encoding src1) 1 0)))))
+
+(define-instruction j (segment src1 &optional src2)
+  (:declare (type tn src1) (type (or tn (signed-byte 13) fixup null) src2))
+  (:printer format-3-reg ((op #b10) (op3 #b111000) (rd 0)) jal-printer)
+  (:printer format-3-immed ((op #b10) (op3 #b111000) (rd 0)) jal-printer)
+  (:attributes branch)
+  (:dependencies (reads src1) (if src2 (reads src2)))
+  (:delay 1)
+  (:emitter
+   (etypecase src2
+     (null
+      (emit-format-3-reg segment #b10 0 #b111000 (reg-tn-encoding src1) 0 0 0))
+     (tn
+      (emit-format-3-reg segment #b10 0 #b111000 (reg-tn-encoding src1) 0 0
+                        (reg-tn-encoding src2)))
+     (integer
+      (emit-format-3-immed segment #b10 0 #b111000 (reg-tn-encoding src1) 1
+                          src2))
+     (fixup
+      (note-fixup segment :add src2)
+      (emit-format-3-immed segment #b10 0 #b111000 (reg-tn-encoding src1) 1
+                          0)))))
+
+
+\f
+;;;; Unary and binary fp insts.
+
+(macrolet ((define-unary-fp-inst (name opf &key reads extended)
+  `(define-instruction ,name (segment dst src)
+     (:declare (type tn dst src))
+     (:printer format-unary-fpop
+       ((op #b10) (op3 #b110100) (opf ,opf)
+       (rs1 0)
+       (rs2 nil :type ',(if extended 'fp-ext-reg 'fp-reg))
+       (rd nil :type ',(if extended 'fp-ext-reg 'fp-reg))))
+     (:dependencies
+      ,@(when reads
+         `((reads ,reads)))
+      (reads dst)
+      (reads src)
+      (writes dst))
+     (:delay 0)
+     (:emitter (emit-format-3-fpop segment #b10 (fp-reg-tn-encoding dst)
+               #b110100 0 ,opf (fp-reg-tn-encoding src)))))
+
+          (define-binary-fp-inst (name opf &key (op3 #b110100)
+                                     reads writes delay extended)
+  `(define-instruction ,name (segment dst src1 src2)
+     (:declare (type tn dst src1 src2))
+     (:printer format-binary-fpop
+      ((op #b10) (op3 ,op3) (opf ,opf)
+       (rs1 nil :type ',(if extended 'fp-ext-reg 'fp-reg))
+       (rs2 nil :type ',(if extended 'fp-ext-reg 'fp-reg))
+       (rd nil :type ',(if extended 'fp-ext-reg 'fp-reg))
+       ))
+     (:dependencies
+      ,@(when reads
+         `((reads ,reads)))
+      (reads src1)
+      (reads src2)
+      ,@(when writes
+         `((writes ,writes)))
+      (writes dst))
+     ,@(if delay
+          `((:delay ,delay))
+          '((:delay 0)))
+     (:emitter (emit-format-3-fpop segment #b10 (fp-reg-tn-encoding dst)
+               ,op3 (fp-reg-tn-encoding src1) ,opf
+               (fp-reg-tn-encoding src2)))))
+
+          (define-cmp-fp-inst (name opf &key extended)
+              (let ((opf0 #b0)
+                    (opf1 #b010)
+                    (opf2 #b1))
+                `(define-instruction ,name (segment src1 src2 &optional (fcc :fcc0))
+                  (:declare (type tn src1 src2)
+                   (type (member :fcc0 :fcc1 :fcc2 :fcc3) fcc))
+       (:printer format-fpop2
+                ((op #b10)
+                 (op3 #b110101)
+                 (opf0 ,opf0)
+                 (opf1 ,opf1)
+                 (opf2 ,opf2)
+                 (opf3 ,opf)
+                 (rs1 nil :type ',(if extended 'fp-ext-reg 'fp-reg))
+                 (rs2 nil :type ',(if extended 'fp-ext-reg 'fp-reg))
+                 #!-sparc-v9
+                 (rd 0)
+                 #!+sparc-v9
+                 (rd nil :type 'fp-condition-register))
+       )
+     (:dependencies
+      (reads src1)
+      (reads src2)
+      (writes :fsr))
+     ;; The Sparc V9 doesn't need a delay after a FP compare.
+     (:delay #!-sparc-v9 1 #!+sparc-v9 0)
+       (:emitter
+       (emit-format-3-fpop2 segment #b10
+                            (or (position fcc '(:fcc0 :fcc1 :fcc2 :fcc3))
+                                0)
+                            #b110101
+                            (fp-reg-tn-encoding src1)
+                            ,opf0 ,opf1 ,opf2 ,opf
+                            (fp-reg-tn-encoding src2)))))))
+
+  (define-unary-fp-inst fitos #b011000100 :reads :fsr)
+  (define-unary-fp-inst fitod #b011001000 :reads :fsr :extended t)
+  (define-unary-fp-inst fitoq #b011001100 :reads :fsr :extended t)     ; v8
+  
+  (define-unary-fp-inst fxtos #b010000100 :reads :fsr)                    ; v9
+  (define-unary-fp-inst fxtod #b010001000 :reads :fsr :extended t)        ; v9
+  (define-unary-fp-inst fxtoq #b010001100 :reads :fsr :extended t)     ; v9
+
+
+  ;; I (toy@rtp.ericsson.se) don't think these f{sd}toir instructions
+  ;; exist on any Ultrasparc, but I only have a V9 manual.  The code in
+  ;; float.lisp seems to indicate that they only existed on non-sun4
+  ;; machines (sun3 68K machines?).
+  (define-unary-fp-inst fstoir #b011000001 :reads :fsr)
+  (define-unary-fp-inst fdtoir #b011000010 :reads :fsr)
+  
+  (define-unary-fp-inst fstoi #b011010001)
+  (define-unary-fp-inst fdtoi #b011010010 :extended t)
+  (define-unary-fp-inst fqtoi #b011010011 :extended t) ; v8
+
+  (define-unary-fp-inst fstox #b010000001)                ; v9
+  (define-unary-fp-inst fdtox #b010000010 :extended t)    ; v9
+  (define-unary-fp-inst fqtox #b010000011 :extended t) ; v9
+
+  (define-unary-fp-inst fstod #b011001001 :reads :fsr)
+  (define-unary-fp-inst fstoq #b011001101 :reads :fsr) ; v8
+  (define-unary-fp-inst fdtos #b011000110 :reads :fsr)
+  (define-unary-fp-inst fdtoq #b011001110 :reads :fsr) ; v8
+  (define-unary-fp-inst fqtos #b011000111 :reads :fsr) ; v8
+  (define-unary-fp-inst fqtod #b011001011 :reads :fsr) ; v8
+  
+  (define-unary-fp-inst fmovs #b000000001)
+  (define-unary-fp-inst fmovd #b000000010 :extended t) ; v9
+  (define-unary-fp-inst fmovq #b000000011 :extended t) ; v9
+  
+  (define-unary-fp-inst fnegs #b000000101)
+  (define-unary-fp-inst fnegd #b000000110 :extended t) ; v9
+  (define-unary-fp-inst fnegq #b000000111 :extended t) ; v9
+
+  (define-unary-fp-inst fabss #b000001001)
+  (define-unary-fp-inst fabsd #b000001010 :extended t) ; v9
+  (define-unary-fp-inst fabsq #b000001011 :extended t) ; v9
+  
+  (define-unary-fp-inst fsqrts #b000101001 :reads :fsr)                ; V7
+  (define-unary-fp-inst fsqrtd #b000101010 :reads :fsr :extended t)    ; V7
+  (define-unary-fp-inst fsqrtq #b000101011 :reads :fsr :extended t)    ; v8
+  
+  (define-binary-fp-inst fadds #b001000001)
+  (define-binary-fp-inst faddd #b001000010 :extended t)
+  (define-binary-fp-inst faddq #b001000011 :extended t)        ; v8
+  (define-binary-fp-inst fsubs #b001000101)
+  (define-binary-fp-inst fsubd #b001000110 :extended t)
+  (define-binary-fp-inst fsubq #b001000111 :extended t)        ; v8
+  
+  (define-binary-fp-inst fmuls #b001001001)
+  (define-binary-fp-inst fmuld #b001001010 :extended t)
+  (define-binary-fp-inst fmulq #b001001011 :extended t)        ; v8
+  (define-binary-fp-inst fdivs #b001001101)
+  (define-binary-fp-inst fdivd #b001001110 :extended t)
+  (define-binary-fp-inst fdivq #b001001111 :extended t)        ; v8
+
+;;; Float comparison instructions.
+;;;
+  (define-cmp-fp-inst fcmps #b0001)
+  (define-cmp-fp-inst fcmpd #b0010 :extended t)
+  (define-cmp-fp-inst fcmpq #b0011 :extended t) ;v8
+  (define-cmp-fp-inst fcmpes #b0101)
+  (define-cmp-fp-inst fcmped #b0110 :extended t)
+  (define-cmp-fp-inst fcmpeq #b0111 :extended t)       ; v8
+
+) ; MACROLET
+\f
+;;;; li, jali, ji, nop, cmp, not, neg, move, and more
+
+(defun %li (reg value)
+  (etypecase value
+    ((signed-byte 13)
+     (inst add reg zero-tn value))
+    ((or (signed-byte 32) (unsigned-byte 32))
+     (let ((hi (ldb (byte 22 10) value))
+          (lo (ldb (byte 10 0) value)))
+       (inst sethi reg hi)
+       (unless (zerop lo)
+        (inst add reg lo))))
+    (fixup
+     (inst sethi reg value)
+     (inst add reg value))))
+
+(define-instruction-macro li (reg value)
+  `(%li ,reg ,value))
+
+;;; Jal to a full 32-bit address.  Tmpreg is trashed.
+(define-instruction jali (segment link tmpreg value)
+  (:declare (type tn link tmpreg)
+           (type (or (signed-byte 13) (signed-byte 32) (unsigned-byte 32)
+                     fixup) value))
+  (:attributes variable-length)
+  (:vop-var vop)
+  (:attributes branch)
+  (:dependencies (writes link) (writes tmpreg))
+  (:delay 1)
+  (:emitter
+   (assemble (segment vop)
+     (etypecase value
+       ((signed-byte 13)
+       (inst jal link zero-tn value))
+       ((or (signed-byte 32) (unsigned-byte 32))
+       (let ((hi (ldb (byte 22 10) value))
+             (lo (ldb (byte 10 0) value)))
+         (inst sethi tmpreg hi)
+         (inst jal link tmpreg lo)))
+       (fixup
+       (inst sethi tmpreg value)
+       (inst jal link tmpreg value))))))
+
+;;; Jump to a full 32-bit address.  Tmpreg is trashed.
+(define-instruction ji (segment tmpreg value)
+  (:declare (type tn tmpreg)
+           (type (or (signed-byte 13) (signed-byte 32) (unsigned-byte 32)
+                     fixup) value))
+  (:attributes variable-length)
+  (:vop-var vop)
+  (:attributes branch)
+  (:dependencies (writes tmpreg))
+  (:delay 1)
+  (:emitter
+   (assemble (segment vop)
+            (inst jali zero-tn tmpreg value))))
+
+(define-instruction nop (segment)
+  (:printer format-2-immed ((rd 0) (op2 #b100) (immed 0)) '(:name))
+  (:attributes flushable)
+  (:delay 0)
+  (:emitter (emit-format-2-immed segment 0 0 #b100 0)))
+
+(!def-vm-support-routine emit-nop (segment)
+  (emit-format-2-immed segment 0 0 #b100 0))
+
+(define-instruction cmp (segment src1 &optional src2)
+  (:declare (type tn src1) (type (or null tn (signed-byte 13)) src2))
+  (:printer format-3-reg ((op #b10) (op3 #b010100) (rd 0))
+            '(:name :tab rs1 ", " rs2))
+  (:printer format-3-immed ((op #b10) (op3 #b010100) (rd 0))
+            '(:name :tab rs1 ", " immed))
+  (:dependencies (reads src1) (if src2 (reads src2)) (writes :psr))
+  (:delay 0)
+  (:emitter
+   (etypecase src2
+     (null
+      (emit-format-3-reg segment #b10 0 #b010100 (reg-tn-encoding src1) 0 0 0))
+     (tn
+      (emit-format-3-reg segment #b10 0 #b010100 (reg-tn-encoding src1) 0 0
+                        (reg-tn-encoding src2)))
+     (integer
+      (emit-format-3-immed segment #b10 0 #b010100 (reg-tn-encoding src1) 1
+                          src2)))))
+
+(define-instruction not (segment dst &optional src1)
+  (:declare (type tn dst) (type (or tn null) src1))
+  (:printer format-3-reg ((op #b10) (op3 #b000111) (rs2 0))
+            '(:name :tab (:unless (:same-as rd) rs1 ", " ) rd))
+  (:dependencies (if src1 (reads src1) (reads dst)) (writes dst))
+  (:delay 0)
+  (:emitter
+   (unless src1
+     (setf src1 dst))
+   (emit-format-3-reg segment #b10 (reg-tn-encoding dst) #b000111
+                     (reg-tn-encoding src1) 0 0 0)))
+
+(define-instruction neg (segment dst &optional src1)
+  (:declare (type tn dst) (type (or tn null) src1))
+  (:printer format-3-reg ((op #b10) (op3 #b000100) (rs1 0))
+            '(:name :tab (:unless (:same-as rd) rs2 ", " ) rd))
+  (:dependencies (if src1 (reads src1) (reads dst)) (writes dst))
+  (:delay 0)
+  (:emitter
+   (unless src1
+     (setf src1 dst))
+   (emit-format-3-reg segment #b10 (reg-tn-encoding dst) #b000100
+                     0 0 0 (reg-tn-encoding src1))))
+
+(define-instruction move (segment dst src1)
+  (:declare (type tn dst src1))
+  (:printer format-3-reg ((op #b10) (op3 #b000010) (rs1 0))
+            '(:name :tab rs2 ", " rd)
+           :print-name 'mov)
+  (:attributes flushable)
+  (:dependencies (reads src1) (writes dst))
+  (:delay 0)
+  (:emitter (emit-format-3-reg segment #b10 (reg-tn-encoding dst) #b000010
+                              0 0 0 (reg-tn-encoding src1))))
+
+
+\f
+;;;; Instructions for dumping data and header objects.
+
+(define-instruction word (segment word)
+  (:declare (type (or (unsigned-byte 32) (signed-byte 32)) word))
+  :pinned
+  (:delay 0)
+  (:emitter
+   (emit-word segment word)))
+
+(define-instruction short (segment short)
+  (:declare (type (or (unsigned-byte 16) (signed-byte 16)) short))
+  :pinned
+  (:delay 0)
+  (:emitter
+   (emit-short segment short)))
+
+(define-instruction byte (segment byte)
+  (:declare (type (or (unsigned-byte 8) (signed-byte 8)) byte))
+  :pinned
+  (:delay 0)
+  (:emitter
+   (emit-byte segment byte)))
+
+(define-bitfield-emitter emit-header-object 32
+  (byte 24 8) (byte 8 0))
+  
+(defun emit-header-data (segment type)
+  (emit-back-patch
+   segment 4
+   (lambda (segment posn)
+       (emit-word segment
+                 (logior type
+                         (ash (+ posn (component-header-length))
+                              (- n-widetag-bits word-shift)))))))
+
+(define-instruction simple-fun-header-word (segment)
+  :pinned
+  (:delay 0)
+  (:emitter
+   (emit-header-data segment simple-fun-header-widetag)))
+
+(define-instruction lra-header-word (segment)
+  :pinned
+  (:delay 0)
+  (:emitter
+   (emit-header-data segment return-pc-header-widetag)))
+
+\f
+;;;; Instructions for converting between code objects, functions, and lras.
+
+(defun emit-compute-inst (segment vop dst src label temp calc)
+  (emit-chooser
+   ;; We emit either 12 or 4 bytes, so we maintain 8 byte alignments.
+   segment 12 3
+   (lambda (segment posn delta-if-after)
+       (let ((delta (funcall calc label posn delta-if-after)))
+        (when (<= (- (ash 1 12)) delta (1- (ash 1 12)))
+          (emit-back-patch segment 4
+                           (lambda (segment posn)
+                               (assemble (segment vop)
+                                         (inst add dst src
+                                               (funcall calc label posn 0)))))
+          t)))
+   (lambda (segment posn)
+       (let ((delta (funcall calc label posn 0)))
+        (assemble (segment vop)
+                  (inst sethi temp (ldb (byte 22 10) delta))
+                  (inst or temp (ldb (byte 10 0) delta))
+                  (inst add dst src temp))))))
+
+;; code = fn - fn-ptr-type - header - label-offset + other-pointer-tag
+(define-instruction compute-code-from-fn (segment dst src label temp)
+  (:declare (type tn dst src temp) (type label label))
+  (:attributes variable-length)
+  (:dependencies (reads src) (writes dst) (writes temp))
+  (:delay 0)
+  (:vop-var vop)
+  (:emitter
+   (emit-compute-inst segment vop dst src label temp
+                     (lambda (label posn delta-if-after)
+                         (- other-pointer-lowtag
+                            fun-pointer-lowtag
+                            (label-position label posn delta-if-after)
+                            (component-header-length))))))
+
+;; code = lra - other-pointer-tag - header - label-offset + other-pointer-tag
+(define-instruction compute-code-from-lra (segment dst src label temp)
+  (:declare (type tn dst src temp) (type label label))
+  (:attributes variable-length)
+  (:dependencies (reads src) (writes dst) (writes temp))
+  (:delay 0)
+  (:vop-var vop)
+  (:emitter
+   (emit-compute-inst segment vop dst src label temp
+                     (lambda (label posn delta-if-after)
+                         (- (+ (label-position label posn delta-if-after)
+                               (component-header-length)))))))
+
+;; lra = code + other-pointer-tag + header + label-offset - other-pointer-tag
+(define-instruction compute-lra-from-code (segment dst src label temp)
+  (:declare (type tn dst src temp) (type label label))
+  (:attributes variable-length)
+  (:dependencies (reads src) (writes dst) (writes temp))
+  (:delay 0)
+  (:vop-var vop)
+  (:emitter
+   (emit-compute-inst segment vop dst src label temp
+                     (lambda (label posn delta-if-after)
+                         (+ (label-position label posn delta-if-after)
+                            (component-header-length))))))
+\f
+;;; Sparc V9 additions
+
+
+
+;; Conditional move integer on condition code
+(define-instruction cmove (segment condition dst src &optional (ccreg :icc))
+  (:declare (type (or branch-condition fp-branch-condition) condition)
+           (type cond-move-condition-register ccreg)
+           (type tn dst)
+           (type (or (signed-byte 13) tn) src))
+  (:printer format-4-cond-move
+           ((op #b10)
+            (op3 #b101100)
+            (cc2 #b1)
+            (i 0)
+            (cc nil :type 'integer-condition-register))
+            cond-move-printer
+            :print-name 'mov)
+  (:printer format-4-cond-move-immed
+           ((op #b10)
+            (op3 #b101100)
+            (cc2 #b1)
+            (i 1)
+            (cc nil :type 'integer-condition-register))
+            cond-move-printer
+            :print-name 'mov)
+  (:printer format-4-cond-move
+           ((op #b10)
+            (op3 #b101100)
+            (cc2 #b0)
+            (cond nil :type 'branch-fp-condition)
+            (i 0)
+            (cc nil :type 'fp-condition-register))
+            cond-move-printer
+            :print-name 'mov)
+  (:printer format-4-cond-move-immed
+           ((op #b10)
+            (op3 #b101100)
+            (cc2 #b0)
+            (cond nil :type 'branch-fp-condition)
+            (i 1)
+            (cc nil :type 'fp-condition-register))
+            cond-move-printer
+            :print-name 'mov)
+  (:delay 0)
+  (:dependencies
+   (if (member ccreg '(:icc :xcc))
+       (reads :psr)
+       (reads :fsr))
+   (reads src)
+   (reads dst)
+   (writes dst))
+  (:emitter
+   (let ((op #b10)
+        (op3 #b101100))
+     (multiple-value-bind (cc2 cc01)
+        (cond-move-condition-parts ccreg)
+       (etypecase src
+        (tn
+         (emit-format-4-cond-move segment
+                                  op
+                                  (reg-tn-encoding dst)
+                                  op3
+                                  cc2
+                                  (if (member ccreg '(:icc :xcc))
+                                      (branch-condition condition)
+                                      (fp-branch-condition condition))
+                                  0
+                                  cc01
+                                  (reg-tn-encoding src)))
+        (integer
+         (emit-format-4-cond-move segment
+                                  op
+                                  (reg-tn-encoding dst)
+                                  op3
+                                  cc2
+                                  (if (member ccreg '(:icc :xcc))
+                                      (branch-condition condition)
+                                      (fp-branch-condition condition))
+                                  1
+                                  cc01
+                                  src)))))))
+
+;; Conditional move floating-point on condition codes
+(macrolet ((define-cond-fp-move (name print-name op op3 opf_low &key extended)
+  `(define-instruction ,name (segment condition dst src &optional (ccreg :fcc0))
+     (:declare (type (or branch-condition fp-branch-condition) condition)
+              (type cond-move-condition-register ccreg)
+              (type tn dst src))
+     (:printer format-fpop2
+              ((op ,op)
+               (op3 ,op3)
+               (opf0 0)
+               (opf1 nil :type 'fp-condition-register-shifted)
+               (opf2 0)
+               (opf3 ,opf_low)
+               (rs1 nil :type 'branch-fp-condition)
+               (rs2 nil :type ',(if extended 'fp-ext-reg 'fp-reg))
+               (rd nil :type ',(if extended 'fp-ext-reg 'fp-reg)))
+                cond-fp-move-printer
+                :print-name ',print-name)
+     (:printer format-fpop2
+              ((op ,op)
+               (op3 ,op3)
+               (opf0 1)
+               (opf1 nil :type 'integer-condition-register)
+               (opf2 0)
+               (rs1 nil :type 'branch-condition)
+               (opf3 ,opf_low)
+               (rs2 nil :type ',(if extended 'fp-ext-reg 'fp-reg))
+               (rd nil :type ',(if extended 'fp-ext-reg 'fp-reg)))
+               cond-fp-move-printer
+               :print-name ',print-name)
+     (:delay 0)
+     (:dependencies
+      (if (member ccreg '(:icc :xcc))
+         (reads :psr)
+         (reads :fsr))
+      (reads src)
+      (reads dst)
+      (writes dst))
+     (:emitter
+      (multiple-value-bind (opf_cc2 opf_cc01)
+         (cond-move-condition-parts ccreg)
+       (emit-format-3-fpop2 segment
+                            ,op
+                            (fp-reg-tn-encoding dst)
+                            ,op3
+                            (if (member ccreg '(:icc :xcc))
+                                (branch-condition condition)
+                                (fp-branch-condition condition))
+                            opf_cc2
+                            (ash opf_cc01 1)
+                            0
+                            ,opf_low
+                            (fp-reg-tn-encoding src)))))))
+  (define-cond-fp-move cfmovs fmovs #b10 #b110101 #b0001)
+  (define-cond-fp-move cfmovd fmovd #b10 #b110101 #b0010 :extended t)
+  (define-cond-fp-move cfmovq fmovq #b10 #b110101 #b0011 :extended t))
+
+
+;; Move on integer register condition
+;;
+;; movr dst src reg reg-cond
+;;
+;; This means if reg satisfies reg-cond, src is copied to dst.  If the
+;; condition is not satisfied, nothing is done.
+;;
+(define-instruction movr (segment dst src2 src1 reg-condition)
+  (:declare (type cond-move-integer-condition reg-condition)
+           (type tn dst src1)
+           (type (or (signed-byte 10) tn) src2))
+  (:printer format-4-cond-move-integer
+           ((op #b10)
+            (op3 #b101111)
+            (i 0)))
+  (:printer format-4-cond-move-integer-immed
+           ((op #b10)
+            (op3 #b101111)
+            (i 1)))
+  (:delay 0)
+  (:dependencies
+   (reads :psr)
+   (reads src2)
+   (reads src1)
+   (reads dst)
+   (writes dst))
+  (:emitter
+   (etypecase src2
+     (tn
+      (emit-format-4-cond-move-integer
+       segment #b10 (reg-tn-encoding dst) #b101111 (reg-tn-encoding src1)
+       0 (register-condition reg-condition)
+       0 (reg-tn-encoding src2)))
+     (integer
+      (emit-format-4-cond-move-integer-immed
+       segment #b10 (reg-tn-encoding dst) #b101111 (reg-tn-encoding src1)
+       1 (register-condition reg-condition) src2)))))
+
+
+;; Same as MOVR, except we move FP registers depending on the value of
+;; an integer register.
+;;
+;; fmovr dst src reg cond
+;;
+;; This means if REG satifies COND, SRC is COPIED to DST.  Nothing
+;; happens if the condition is not satisfied.
+(macrolet ((define-cond-fp-move-integer (name opf_low &key extended)
+  `(define-instruction ,name (segment dst src2 src1 reg-condition)
+     (:declare (type cond-move-integer-condition reg-condition)
+              (type tn dst src1 src2))
+     (:printer format-fpop2
+              ((op #b10)
+               (rd nil :type ',(if extended 'fp-ext-reg 'fp-reg))
+               (op3 #b110101)
+               (rs1 nil :type 'reg)
+               (opf0 0)
+               (opf1 nil :type 'register-condition)
+               (opf2 0)
+               (opf3 ,opf_low)
+               (rs2 nil :type ',(if extended 'fp-ext-reg 'fp-reg))
+               )
+               cond-fp-move-integer-printer)
+     (:delay 0)
+     (:dependencies
+      (reads src2)
+      (reads src1)
+      (reads dst)
+      (writes dst))
+     (:emitter
+      (emit-format-3-fpop2
+       segment
+       #b10
+       (fp-reg-tn-encoding dst)
+       #b110101
+       (reg-tn-encoding src1)
+       0
+       (register-condition reg-condition)
+       0
+       ,opf_low
+       (fp-reg-tn-encoding src2))))))
+  (define-cond-fp-move-integer fmovrs #b0101)
+  (define-cond-fp-move-integer fmovrd #b0110 :extended t)
+  (define-cond-fp-move-integer fmovrq #b0111 :extended t))
diff --git a/src/compiler/sparc/macros.lisp b/src/compiler/sparc/macros.lisp
new file mode 100644 (file)
index 0000000..d0b30b7
--- /dev/null
@@ -0,0 +1,445 @@
+;;;; various useful macros for generating Sparc code
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;; Instruction-like macros.
+
+(defmacro move (dst src)
+  "Move SRC into DST unless they are location=."
+  (once-only ((n-dst dst)
+             (n-src src))
+    `(unless (location= ,n-dst ,n-src)
+       (inst move ,n-dst ,n-src))))
+
+(macrolet
+    ((frob (op inst shift)
+       `(defmacro ,op (object base &optional (offset 0) (lowtag 0))
+         `(inst ,',inst ,object ,base (- (ash ,offset ,,shift) ,lowtag)))))
+  (frob loadw ld word-shift)
+  (frob storew st word-shift))
+
+(defmacro load-symbol (reg symbol)
+  `(inst add ,reg null-tn (static-symbol-offset ,symbol)))
+
+(macrolet
+    ((frob (slot)
+       (let ((loader (intern (concatenate 'simple-string
+                                         "LOAD-SYMBOL-"
+                                         (string slot))))
+            (storer (intern (concatenate 'simple-string
+                                         "STORE-SYMBOL-"
+                                         (string slot))))
+            (offset (intern (concatenate 'simple-string
+                                         "SYMBOL-"
+                                         (string slot)
+                                         "-SLOT")
+                            (find-package "SB!VM"))))
+        `(progn
+           (defmacro ,loader (reg symbol)
+             `(inst ld ,reg null-tn
+                    (+ (static-symbol-offset ',symbol)
+                       (ash ,',offset word-shift)
+                       (- other-pointer-lowtag))))
+           (defmacro ,storer (reg symbol)
+             `(inst st ,reg null-tn
+                    (+ (static-symbol-offset ',symbol)
+                       (ash ,',offset word-shift)
+                       (- other-pointer-lowtag))))))))
+  (frob value)
+  (frob function))
+
+(defmacro load-type (target source &optional (offset 0))
+  #!+sb-doc
+  "Loads the type bits of a pointer into target independent of
+  byte-ordering issues."
+  (once-only ((n-target target)
+             (n-source source)
+             (n-offset offset))
+    ;; FIXME: although I don't understand entirely, I'm going to do
+    ;; what whn does in x86/macros.lisp -- Christophe
+    (ecase *backend-byte-order*
+      (:little-endian
+       `(inst ldub ,n-target ,n-source ,n-offset))
+      (:big-endian
+       `(inst ldub ,n-target ,n-source (+ ,n-offset 3))))))
+
+;;; Macros to handle the fact that we cannot use the machine native call and
+;;; return instructions. 
+
+(defmacro lisp-jump (fun)
+  "Jump to the lisp function FUNCTION.  LIP is an interior-reg temporary."
+  `(progn
+     (inst j ,fun
+          (- (ash simple-fun-code-offset word-shift) fun-pointer-lowtag))
+     (move code-tn ,fun)))
+
+(defmacro lisp-return (return-pc &key (offset 0) (frob-code t))
+  "Return to RETURN-PC."
+  `(progn
+     (inst j ,return-pc
+          (- (* (1+ ,offset) n-word-bytes) other-pointer-lowtag))
+     ,(if frob-code
+         `(move code-tn ,return-pc)
+         '(inst nop))))
+
+(defmacro emit-return-pc (label)
+  "Emit a return-pc header word.  LABEL is the label to use for this return-pc."
+  `(progn
+     (align n-lowtag-bits)
+     (emit-label ,label)
+     (inst lra-header-word)))
+
+
+\f
+;;;; Stack TN's
+
+;;; Load-Stack-TN, Store-Stack-TN  --  Interface
+;;;
+;;;    Move a stack TN to a register and vice-versa.
+;;;
+(defmacro load-stack-tn (reg stack)
+  `(let ((reg ,reg)
+        (stack ,stack))
+     (let ((offset (tn-offset stack)))
+       (sc-case stack
+        ((control-stack)
+         (loadw reg cfp-tn offset))))))
+
+(defmacro store-stack-tn (stack reg)
+  `(let ((stack ,stack)
+        (reg ,reg))
+     (let ((offset (tn-offset stack)))
+       (sc-case stack
+        ((control-stack)
+         (storew reg cfp-tn offset))))))
+
+
+;;; MAYBE-LOAD-STACK-TN  --  Interface
+;;;
+(defmacro maybe-load-stack-tn (reg reg-or-stack)
+  "Move the TN Reg-Or-Stack into Reg if it isn't already there."
+  (once-only ((n-reg reg)
+             (n-stack reg-or-stack))
+    `(sc-case ,n-reg
+       ((any-reg descriptor-reg)
+       (sc-case ,n-stack
+         ((any-reg descriptor-reg)
+          (move ,n-reg ,n-stack))
+         ((control-stack)
+          (loadw ,n-reg cfp-tn (tn-offset ,n-stack))))))))
+
+\f
+;;;; Storage allocation:
+
+(defmacro with-fixed-allocation ((result-tn temp-tn type-code size)
+                                &body body)
+  "Do stuff to allocate an other-pointer object of fixed Size with a single
+  word header having the specified Type-Code.  The result is placed in
+  Result-TN, and Temp-TN is a non-descriptor temp (which may be randomly used
+  by the body.)  The body is placed inside the PSEUDO-ATOMIC, and presumably
+  initializes the object."
+  (once-only ((result-tn result-tn) (temp-tn temp-tn)
+             (type-code type-code) (size size))
+    `(pseudo-atomic (:extra (pad-data-block ,size))
+       (inst or ,result-tn alloc-tn other-pointer-lowtag)
+       (inst li ,temp-tn (logior (ash (1- ,size) n-widetag-bits) ,type-code))
+       (storew ,temp-tn ,result-tn 0 other-pointer-lowtag)
+       ,@body)))
+
+\f
+;;;; Error Code
+
+(defvar *adjustable-vectors* nil)
+
+(defmacro with-adjustable-vector ((var) &rest body)
+  `(let ((,var (or (pop *adjustable-vectors*)
+                  (make-array 16
+                              :element-type '(unsigned-byte 8)
+                              :fill-pointer 0
+                              :adjustable t))))
+     (setf (fill-pointer ,var) 0)
+     (unwind-protect
+        (progn
+          ,@body)
+       (push ,var *adjustable-vectors*))))
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+  (defun emit-error-break (vop kind code values)
+    (let ((vector (gensym)))
+      `((let ((vop ,vop))
+         (when vop
+           (note-this-location vop :internal-error)))
+       (inst unimp ,kind)
+       (with-adjustable-vector (,vector)
+         (write-var-integer (error-number-or-lose ',code) ,vector)
+         ,@(mapcar #'(lambda (tn)
+                       `(let ((tn ,tn))
+                          (write-var-integer (make-sc-offset (sc-number
+                                                              (tn-sc tn))
+                                                             (tn-offset tn))
+                                             ,vector)))
+                   values)
+         (inst byte (length ,vector))
+         (dotimes (i (length ,vector))
+           (inst byte (aref ,vector i))))
+       (align word-shift)))))
+
+(defmacro error-call (vop error-code &rest values)
+  "Cause an error.  ERROR-CODE is the error to cause."
+  (cons 'progn
+       (emit-error-break vop error-trap error-code values)))
+
+
+(defmacro cerror-call (vop label error-code &rest values)
+  "Cause a continuable error.  If the error is continued, execution resumes at
+  LABEL."
+  `(progn
+     (inst b ,label)
+     ,@(emit-error-break vop cerror-trap error-code values)))
+
+(defmacro generate-error-code (vop error-code &rest values)
+  "Generate-Error-Code Error-code Value*
+  Emit code for an error with the specified Error-Code and context Values."
+  `(assemble (*elsewhere*)
+     (let ((start-lab (gen-label)))
+       (emit-label start-lab)
+       (error-call ,vop ,error-code ,@values)
+       start-lab)))
+
+(defmacro generate-cerror-code (vop error-code &rest values)
+  "Generate-CError-Code Error-code Value*
+  Emit code for a continuable error with the specified Error-Code and
+  context Values.  If the error is continued, execution resumes after
+  the GENERATE-CERROR-CODE form."
+  (let ((continue (gensym "CONTINUE-LABEL-"))
+       (error (gensym "ERROR-LABEL-")))
+    `(let ((,continue (gen-label)))
+       (emit-label ,continue)
+       (assemble (*elsewhere*)
+        (let ((,error (gen-label)))
+          (emit-label ,error)
+          (cerror-call ,vop ,continue ,error-code ,@values)
+          ,error)))))
+
+
+\f
+;;; PSEUDO-ATOMIC -- Handy macro for making sequences look atomic.
+;;;
+(defmacro pseudo-atomic ((&key (extra 0)) &rest forms)
+  (let ((n-extra (gensym)))
+    `(let ((,n-extra ,extra))
+       ;; Set the pseudo-atomic flag
+       (without-scheduling ()
+        (inst add alloc-tn 4))
+       ,@forms
+       ;; Reset the pseudo-atomic flag
+       (without-scheduling ()
+        #+nil (inst taddcctv alloc-tn (- ,n-extra 4))
+       ;; Remove the pseudo-atomic flag
+       (inst add alloc-tn (- ,n-extra 4))
+       ;; Check to see if pseudo-atomic interrupted flag is set (bit 0 = 1)
+       (inst andcc zero-tn alloc-tn 3)
+       ;; The C code needs to process this correctly and fixup alloc-tn.
+       (inst t :ne pseudo-atomic-trap)
+       ))))
+
+;;; FIXME: test typing macros. Should(?) be in type-vops.lisp, except
+;;; that they're also used in subprim.lisp
+
+(defun cost-to-test-types (type-codes)
+  (+ (* 2 (length type-codes))
+     (if (> (apply #'max type-codes) lowtag-limit) 7 2)))
+
+(defparameter *immediate-types*
+  (list base-char-widetag unbound-marker-widetag))
+
+(defparameter *fun-header-widetags*
+  (list funcallable-instance-header-widetag
+       simple-fun-header-widetag
+       closure-fun-header-widetag
+       closure-header-widetag))
+
+(defun gen-range-test (reg target not-target not-p min seperation max values)
+  (let ((tests nil)
+       (start nil)
+       (end nil)
+       (insts nil))
+    (multiple-value-bind (equal less-or-equal greater-or-equal label)
+       (if not-p
+           (values :ne :gt :lt not-target)
+           (values :eq :le :ge target))
+      (flet ((emit-test ()
+              (if (= start end)
+                  (push start tests)
+                  (push (cons start end) tests))))
+       (dolist (value values)
+         (cond ((< value min)
+                (error "~S is less than the specified minimum of ~S"
+                       value min))
+               ((> value max)
+                (error "~S is greater than the specified maximum of ~S"
+                       value max))
+               ((not (zerop (rem (- value min) seperation)))
+                (error "~S isn't an even multiple of ~S from ~S"
+                       value seperation min))
+               ((null start)
+                (setf start value))
+               ((> value (+ end seperation))
+                (emit-test)
+                (setf start value)))
+         (setf end value))
+       (emit-test))
+      (macrolet ((inst (name &rest args)
+                  `(push (list 'inst ',name ,@args) insts)))
+       (do ((remaining (nreverse tests) (cdr remaining)))
+           ((null remaining))
+         (let ((test (car remaining))
+               (last (null (cdr remaining))))
+           (if (atom test)
+               (progn
+                 (inst cmp reg test)
+                 (if last
+                     (inst b equal target)
+                     (inst b :eq label)))
+               (let ((start (car test))
+                     (end (cdr test)))
+                 (cond ((and (= start min) (= end max))
+                        (warn "The values ~S cover the entire range from ~
+                        ~S to ~S [step ~S]."
+                              values min max seperation)
+                        (push `(unless ,not-p (inst b ,target)) insts))
+                       ((= start min)
+                        (inst cmp reg end)
+                        (if last
+                            (inst b less-or-equal target)
+                            (inst b :le label)))
+                       ((= end max)
+                        (inst cmp reg start)
+                        (if last
+                            (inst b greater-or-equal target)
+                            (inst b :ge label)))
+                       (t
+                        (inst cmp reg start)
+                        (inst b :lt (if not-p target not-target))
+                        (inst cmp reg end)
+                        (if last
+                            (inst b less-or-equal target)
+                            (inst b :le label))))))))))
+    (nreverse insts)))
+
+(defun gen-other-immediate-test (reg target not-target not-p values)
+  (gen-range-test reg target not-target not-p
+                 (+ other-immediate-0-lowtag lowtag-limit)
+                 (- other-immediate-1-lowtag other-immediate-0-lowtag)
+                 (ash 1 n-widetag-bits)
+                 values))
+
+(defun test-type-aux (reg temp target not-target not-p lowtags immed hdrs
+                     function-p)
+  (let* ((fixnump (and (member even-fixnum-lowtag lowtags :test #'eql)
+                      (member odd-fixnum-lowtag lowtags :test #'eql)))
+        (lowtags (sort (if fixnump
+                           (delete even-fixnum-lowtag
+                                   (remove odd-fixnum-lowtag lowtags
+                                           :test #'eql)
+                                   :test #'eql)
+                           (copy-list lowtags))
+                       #'<))
+        (lowtag (if function-p
+                    fun-pointer-lowtag
+                    other-pointer-lowtag))
+        (hdrs (sort (copy-list hdrs) #'<))
+        (immed (sort (copy-list immed) #'<)))
+    (append
+     (when immed
+       `((inst and ,temp ,reg widetag-mask)
+        ,@(if (or fixnump lowtags hdrs)
+              (let ((fall-through (gensym)))
+                `((let (,fall-through (gen-label))
+                    ,@(gen-other-immediate-test
+                       temp (if not-p not-target target)
+                       fall-through nil immed)
+                    (emit-label ,fall-through))))
+              (gen-other-immediate-test temp target not-target not-p immed))))
+     (when fixnump
+       `((inst andcc zero-tn ,reg fixnum-tag-mask)
+        ,(if (or lowtags hdrs)
+             `(inst b :eq ,(if not-p not-target target)
+               #!+sparc-v9 ,(if not-p :pn :pt))
+             `(inst b ,(if not-p :ne :eq) ,target
+               #!+sparc-v9 ,(if not-p :pn :pt)))))
+     (when (or lowtags hdrs)
+       `((inst and ,temp ,reg lowtag-mask)))
+     (when lowtags
+       (if hdrs
+          (let ((fall-through (gensym)))
+            `((let ((,fall-through (gen-label)))
+                ,@(gen-range-test temp (if not-p not-target target)
+                                  fall-through nil
+                                  0 1 (1- lowtag-limit) lowtags)
+                (emit-label ,fall-through))))
+          (gen-range-test temp target not-target not-p 0 1
+                          (1- lowtag-limit) lowtags)))
+     (when hdrs
+       `((inst cmp ,temp ,lowtag)
+        (inst b :ne ,(if not-p target not-target)
+         #!+sparc-v9 ,(if not-p :pn :pt))
+        (inst nop)
+        (load-type ,temp ,reg (- ,lowtag))
+        ,@(gen-other-immediate-test temp target not-target not-p hdrs))))))
+
+(defmacro test-type (register temp target not-p &rest type-codes)
+  (let* ((type-codes (mapcar #'eval type-codes))
+        (lowtags (remove lowtag-limit type-codes :test #'<))
+        (extended (remove lowtag-limit type-codes :test #'>))
+        (immediates (intersection extended *immediate-types* :test #'eql))
+        (headers (set-difference extended *immediate-types* :test #'eql))
+        (function-p nil))
+    (unless type-codes
+      (error "Must supply at least on type for test-type."))
+    (when (and headers (member other-pointer-lowtag lowtags))
+      (warn "OTHER-POINTER-TYPE supersedes the use of ~S" headers)
+      (setf headers nil))
+    (when (and immediates
+              (or (member other-immediate-0-lowtag lowtags)
+                  (member other-immediate-1-lowtag lowtags)))
+      (warn "OTHER-IMMEDIATE-n-TYPE supersedes the use of ~S" immediates)
+      (setf immediates nil))
+    (when (intersection headers *fun-header-widetags*)
+      (unless (subsetp headers *fun-header-widetags*)
+       (error "Can't test for mix of function subtypes and normal ~
+               header types."))
+      (setq function-p t))
+    
+    (let ((n-reg (gensym))
+         (n-temp (gensym))
+         (n-target (gensym))
+         (not-target (gensym)))
+      `(let ((,n-reg ,register)
+            (,n-temp ,temp)
+            (,n-target ,target)
+            (,not-target (gen-label)))
+       (declare (ignorable ,n-temp))
+       ,@(if (constantp not-p)
+             (test-type-aux n-reg n-temp n-target not-target
+                            (eval not-p) lowtags immediates headers
+                            function-p)
+             `((cond (,not-p
+                      ,@(test-type-aux n-reg n-temp n-target not-target t
+                                       lowtags immediates headers
+                                       function-p))
+                     (t
+                      ,@(test-type-aux n-reg n-temp n-target not-target nil
+                                       lowtags immediates headers
+                                       function-p)))))
+       (inst nop)
+       (emit-label ,not-target)))))
diff --git a/src/compiler/sparc/memory.lisp b/src/compiler/sparc/memory.lisp
new file mode 100644 (file)
index 0000000..8971960
--- /dev/null
@@ -0,0 +1,99 @@
+;;;; the Sparc definitions of some general purpose memory reference
+;;;; VOPs inherited by basic memory reference operations
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+;;; Cell-Ref and Cell-Set are used to define VOPs like CAR, where the
+;;; offset to be read or written is a property of the VOP used.
+(define-vop (cell-ref)
+  (:args (object :scs (descriptor-reg)))
+  (:results (value :scs (descriptor-reg any-reg)))
+  (:variant-vars offset lowtag)
+  (:policy :fast-safe)
+  (:generator 4
+    (loadw value object offset lowtag)))
+
+(define-vop (cell-set)
+  (:args (object :scs (descriptor-reg))
+         (value :scs (descriptor-reg any-reg)))
+  (:variant-vars offset lowtag)
+  (:policy :fast-safe)
+  (:generator 4
+    (storew value object offset lowtag)))
+
+;;; Slot-Ref and Slot-Set are used to define VOPs like Closure-Ref,
+;;; where the offset is constant at compile time, but varies for
+;;; different uses.  We add in the stardard g-vector overhead.
+(define-vop (slot-ref)
+  (:args (object :scs (descriptor-reg)))
+  (:results (value :scs (descriptor-reg any-reg)))
+  (:variant-vars base lowtag)
+  (:info offset)
+  (:generator 4
+    (loadw value object (+ base offset) lowtag)))
+
+(define-vop (slot-set)
+  (:args (object :scs (descriptor-reg))
+        (value :scs (descriptor-reg any-reg)))
+  (:variant-vars base lowtag)
+  (:info offset)
+  (:generator 4
+    (storew value object (+ base offset) lowtag)))
+\f
+;;;; Indexed references:
+
+;;; Define some VOPs for indexed memory reference.
+(macrolet ((define-indexer (name write-p op shift)
+              `(define-vop (,name)
+                (:args (object :scs (descriptor-reg))
+                 (index :scs (any-reg zero immediate))
+                 ,@(when write-p
+                         '((value :scs (any-reg descriptor-reg) :target result))))
+                (:arg-types * tagged-num ,@(when write-p '(*)))
+                (:temporary (:scs (non-descriptor-reg)) temp)
+                (:results (,(if write-p 'result 'value)
+                           :scs (any-reg descriptor-reg)))
+                (:result-types *)
+                (:variant-vars offset lowtag)
+                (:policy :fast-safe)
+                (:generator 5
+                 (sc-case index
+                  ((immediate zero)
+                   (let ((offset (- (+ (if (sc-is index zero)
+                                           0
+                                           (ash (tn-value index)
+                                                (- word-shift ,shift)))
+                                       (ash offset word-shift))
+                                    lowtag)))
+                     (etypecase offset
+                       ((signed-byte 13)
+                        (inst ,op value object offset))
+                       ((or (unsigned-byte 32) (signed-byte 32))
+                        (inst li temp offset)
+                        (inst ,op value object temp)))))
+                  (t
+                   ,@(unless (zerop shift)
+                             `((inst srl temp index ,shift)))
+                   (inst add temp ,(if (zerop shift) 'index 'temp)
+                         (- (ash offset word-shift) lowtag))
+                   (inst ,op value object temp)))
+                 ,@(when write-p
+                         '((move result value)))))))
+  (define-indexer word-index-ref nil ld 0)
+  (define-indexer word-index-set t st 0)
+  (define-indexer halfword-index-ref nil lduh 1)
+  (define-indexer signed-halfword-index-ref nil ldsh 1)
+  (define-indexer halfword-index-set t sth 1)
+  (define-indexer byte-index-ref nil ldub 2)
+  (define-indexer signed-byte-index-ref nil ldsb 2)
+  (define-indexer byte-index-set t stb 2))
+
diff --git a/src/compiler/sparc/move.lisp b/src/compiler/sparc/move.lisp
new file mode 100644 (file)
index 0000000..f3b7566
--- /dev/null
@@ -0,0 +1,301 @@
+;;;; the Sparc VM definition of operand loading/saving and the Move VOP
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+(define-move-fun (load-immediate 1) (vop x y)
+  ((null immediate zero)
+   (any-reg descriptor-reg))
+  (let ((val (tn-value x)))
+    (etypecase val
+      (integer
+       (inst li y (fixnumize val)))
+      (null
+       (move y null-tn))
+      (symbol
+       (load-symbol y val))
+      (character
+       (inst li y (logior (ash (char-code val) n-widetag-bits)
+                         base-char-widetag))))))
+
+(define-move-fun (load-number 1) (vop x y)
+  ((immediate zero)
+   (signed-reg unsigned-reg))
+  (inst li y (tn-value x)))
+
+(define-move-fun (load-base-char 1) (vop x y)
+  ((immediate) (base-char-reg))
+  (inst li y (char-code (tn-value x))))
+
+(define-move-fun (load-system-area-pointer 1) (vop x y)
+  ((immediate) (sap-reg))
+  (inst li y (sap-int (tn-value x))))
+
+(define-move-fun (load-constant 5) (vop x y)
+  ((constant) (descriptor-reg))
+  (loadw y code-tn (tn-offset x) other-pointer-lowtag))
+
+(define-move-fun (load-stack 5) (vop x y)
+  ((control-stack) (any-reg descriptor-reg))
+  (load-stack-tn y x))
+
+(define-move-fun (load-number-stack 5) (vop x y)
+  ((base-char-stack) (base-char-reg)
+   (sap-stack) (sap-reg)
+   (signed-stack) (signed-reg)
+   (unsigned-stack) (unsigned-reg))
+  (let ((nfp (current-nfp-tn vop)))
+    (loadw y nfp (tn-offset x))))
+
+(define-move-fun (store-stack 5) (vop x y)
+  ((any-reg descriptor-reg) (control-stack))
+  (store-stack-tn y x))
+
+(define-move-fun (store-number-stack 5) (vop x y)
+  ((base-char-reg) (base-char-stack)
+   (sap-reg) (sap-stack)
+   (signed-reg) (signed-stack)
+   (unsigned-reg) (unsigned-stack))
+  (let ((nfp (current-nfp-tn vop)))
+    (storew x nfp (tn-offset y))))
+
+\f
+;;;; The Move VOP:
+
+(define-vop (move)
+  (:args (x :target y
+           :scs (any-reg descriptor-reg zero null)
+           :load-if (not (location= x y))))
+  (:results (y :scs (any-reg descriptor-reg)
+              :load-if (not (location= x y))))
+  (:effects)
+  (:affected)
+  (:generator 0
+    (move y x)))
+
+(define-move-vop move :move
+  (any-reg descriptor-reg)
+  (any-reg descriptor-reg))
+
+;;; Make Move the check VOP for T so that type check generation
+;;; doesn't think it is a hairy type.  This also allows checking of a
+;;; few of the values in a continuation to fall out.
+(primitive-type-vop move (:check) t)
+
+;;; The Move-Arg VOP is used for moving descriptor values into
+;;; another frame for argument or known value passing.
+(define-vop (move-arg)
+  (:args (x :target y
+           :scs (any-reg descriptor-reg zero null))
+        (fp :scs (any-reg)
+            :load-if (not (sc-is y any-reg descriptor-reg))))
+  (:results (y))
+  (:generator 0
+    (sc-case y
+      ((any-reg descriptor-reg)
+       (move y x))
+      (control-stack
+       (storew x fp (tn-offset y))))))
+
+(define-move-vop move-arg :move-arg
+  (any-reg descriptor-reg)
+  (any-reg descriptor-reg))
+\f
+;;;; ILLEGAL-MOVE
+
+;;; This VOP exists just to begin the lifetime of a TN that couldn't
+;;; be written legally due to a type error.  An error is signalled
+;;; before this VOP is so we don't need to do anything (not that there
+;;; would be anything sensible to do anyway.)
+(define-vop (illegal-move)
+  (:args (x) (type))
+  (:results (y))
+  (:ignore y)
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:generator 666
+    (error-call vop object-not-type-error x type)))
+\f
+;;;; moves and coercions:
+
+;;; These MOVE-TO-WORD VOPs move a tagged integer to a raw full-word
+;;; representation.  Similarly, the MOVE-FROM-WORD VOPs converts a raw
+;;; integer to a tagged bignum or fixnum.
+
+;;; Arg is a fixnum, so just shift it.  We need a type restriction
+;;; because some possible arg SCs (control-stack) overlap with
+;;; possible bignum arg SCs.
+(define-vop (move-to-word/fixnum)
+  (:args (x :scs (any-reg descriptor-reg)))
+  (:results (y :scs (signed-reg unsigned-reg)))
+  (:arg-types tagged-num)
+  (:note "fixnum untagging")
+  (:generator 1
+    (inst sra y x fixnum-tag-bits)))
+
+(define-move-vop move-to-word/fixnum :move
+  (any-reg descriptor-reg) (signed-reg unsigned-reg))
+
+;;; Arg is a non-immediate constant, load it.
+(define-vop (move-to-word-c)
+  (:args (x :scs (constant)))
+  (:results (y :scs (signed-reg unsigned-reg)))
+  (:note "constant load")
+  (:generator 1
+    (inst li y (tn-value x))))
+
+(define-move-vop move-to-word-c :move
+  (constant) (signed-reg unsigned-reg))
+
+
+;;; Arg is a fixnum or bignum, figure out which and load if necessary.
+(define-vop (move-to-word/integer)
+  (:args (x :scs (descriptor-reg)))
+  (:results (y :scs (signed-reg unsigned-reg)))
+  (:note "integer to untagged word coercion")
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:generator 4
+    (let ((done (gen-label)))
+      (inst andcc temp x fixnum-tag-mask)
+      (inst b :eq done)
+      (inst sra y x fixnum-tag-bits)
+      
+      (loadw y x bignum-digits-offset other-pointer-lowtag)
+      
+      (emit-label done))))
+
+(define-move-vop move-to-word/integer :move
+  (descriptor-reg) (signed-reg unsigned-reg))
+
+;;; Result is a fixnum, so we can just shift.  We need the result type
+;;; restriction because of the control-stack ambiguity noted above.
+(define-vop (move-from-word/fixnum)
+  (:args (x :scs (signed-reg unsigned-reg)))
+  (:results (y :scs (any-reg descriptor-reg)))
+  (:result-types tagged-num)
+  (:note "fixnum tagging")
+  (:generator 1
+    (inst sll y x fixnum-tag-bits)))
+
+(define-move-vop move-from-word/fixnum :move
+  (signed-reg unsigned-reg) (any-reg descriptor-reg))
+
+
+;;; Result may be a bignum, so we have to check.  Use a worst-case
+;;; cost to make sure people know they may be number consing.
+(define-vop (move-from-signed)
+  (:args (arg :scs (signed-reg unsigned-reg) :target x))
+  (:results (y :scs (any-reg descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) x temp)
+  (:note "signed word to integer coercion")
+  (:generator 20
+    (move x arg)
+    (let ((fixnum (gen-label))
+         (done (gen-label)))
+      (inst sra temp x positive-fixnum-bits)
+      (inst cmp temp)
+      (inst b :eq fixnum)
+      (inst orncc temp zero-tn temp)
+      (inst b :eq done)
+      (inst sll y x fixnum-tag-bits)
+      
+      (with-fixed-allocation
+       (y temp bignum-widetag (1+ bignum-digits-offset))
+       (storew x y bignum-digits-offset other-pointer-lowtag))
+      (inst b done)
+      (inst nop)
+      
+      (emit-label fixnum)
+      (inst sll y x fixnum-tag-bits)
+      (emit-label done))))
+
+(define-move-vop move-from-signed :move
+  (signed-reg) (descriptor-reg))
+
+
+;;; Check for fixnum, and possibly allocate one or two word bignum
+;;; result.  Use a worst-case cost to make sure people know they may
+;;; be number consing.
+(define-vop (move-from-unsigned)
+  (:args (arg :scs (signed-reg unsigned-reg) :target x))
+  (:results (y :scs (any-reg descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) x temp)
+  (:note "unsigned word to integer coercion")
+  (:generator 20
+    (move x arg)
+    (let ((done (gen-label))
+         (one-word (gen-label))
+         (initial-alloc (pad-data-block (1+ bignum-digits-offset))))
+      (inst sra temp x positive-fixnum-bits)
+      (inst cmp temp)
+      (inst b :eq done)
+      (inst sll y x fixnum-tag-bits)
+
+      ;; We always allocate 2 words even if we don't need it.  (The
+      ;; copying GC will take care of freeing the unused extra word.)
+      (with-fixed-allocation
+         (y temp bignum-widetag (+ 2 bignum-digits-offset))
+       (inst cmp x)
+       (inst b :ge one-word)
+       (inst li temp (logior (ash 1 n-widetag-bits) bignum-widetag))
+       (inst li temp (logior (ash 2 n-widetag-bits) bignum-widetag))
+       (emit-label one-word)
+       ;; Set the header word, then the actual digit.  The extra
+       ;; digit, if any, is automatically set to zero, so we don't
+       ;; have to.
+       (storew temp y 0 other-pointer-lowtag)
+       (storew x y bignum-digits-offset other-pointer-lowtag))
+      (emit-label done))))
+
+(define-move-vop move-from-unsigned :move
+  (unsigned-reg) (descriptor-reg))
+
+
+;;; Move untagged numbers.
+(define-vop (word-move)
+  (:args (x :target y
+           :scs (signed-reg unsigned-reg)
+           :load-if (not (location= x y))))
+  (:results (y :scs (signed-reg unsigned-reg)
+              :load-if (not (location= x y))))
+  (:effects)
+  (:affected)
+  (:note "word integer move")
+  (:generator 0
+    (move y x)))
+
+(define-move-vop word-move :move
+  (signed-reg unsigned-reg) (signed-reg unsigned-reg))
+
+
+;;; Move untagged number arguments/return-values.
+(define-vop (move-word-arg)
+  (:args (x :target y
+           :scs (signed-reg unsigned-reg))
+        (fp :scs (any-reg)
+            :load-if (not (sc-is y sap-reg))))
+  (:results (y))
+  (:note "word integer argument move")
+  (:generator 0
+    (sc-case y
+      ((signed-reg unsigned-reg)
+       (move y x))
+      ((signed-stack unsigned-stack)
+       (storew x fp (tn-offset y))))))
+
+(define-move-vop move-word-arg :move-arg
+  (descriptor-reg any-reg signed-reg unsigned-reg) (signed-reg unsigned-reg))
+
+
+;;; Use standard MOVE-ARGUMENT + coercion to move an untagged number
+;;; to a descriptor passing location.
+(define-move-vop move-arg :move-arg
+  (signed-reg unsigned-reg) (any-reg descriptor-reg))
diff --git a/src/compiler/sparc/nlx.lisp b/src/compiler/sparc/nlx.lisp
new file mode 100644 (file)
index 0000000..2b63b13
--- /dev/null
@@ -0,0 +1,268 @@
+;;;; the definitions of VOPs used for non-local exit (throw, lexical
+;;;; exit, etc.)
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+;;; Make an environment-live stack TN for saving the SP for NLX entry.
+(!def-vm-support-routine make-nlx-sp-tn (env)
+  (physenv-live-tn
+   (make-representation-tn *fixnum-primitive-type* immediate-arg-scn)
+   env))
+
+;;; Make a TN for the argument count passing location for a non-local
+;;; entry.
+(!def-vm-support-routine make-nlx-entry-arg-start-location ()
+  (make-wired-tn *fixnum-primitive-type* immediate-arg-scn ocfp-offset))
+\f
+;;; save and restore dynamic environment.
+;;;
+;;; These VOPs are used in the reentered function to restore the
+;;; appropriate dynamic environment.  Currently we only save the
+;;; CURRENT-CATCH and binding stack pointer.  We don't need to
+;;; save/restore the current UNWIND-PROTECT, since UNWIND-PROTECTs are
+;;; implicitly processed during unwinding.  If there were any
+;;; additional stacks, then this would be the place to restore the top
+;;; pointers.
+
+
+;;; Return a list of TNs that can be used to snapshot the dynamic
+;;; state for use with the Save/Restore-Dynamic-Environment VOPs.
+(!def-vm-support-routine make-dynamic-state-tns ()
+  (make-n-tns 4 *backend-t-primitive-type*))
+
+(define-vop (save-dynamic-state)
+    (:results (catch :scs (descriptor-reg))
+             (nfp :scs (descriptor-reg))
+             (nsp :scs (descriptor-reg))
+             (eval :scs (descriptor-reg)))
+  (:vop-var vop)
+  (:generator 13
+             (load-symbol-value catch *current-catch-block*)
+             (let ((cur-nfp (current-nfp-tn vop)))
+               (when cur-nfp
+                 (move nfp cur-nfp)))
+             (move nsp nsp-tn)))
+
+(define-vop (restore-dynamic-state)
+    (:args (catch :scs (descriptor-reg))
+          (nfp :scs (descriptor-reg))
+          (nsp :scs (descriptor-reg))
+          (eval :scs (descriptor-reg)))
+  (:vop-var vop)
+  (:generator 10
+             (store-symbol-value catch *current-catch-block*)
+             (let ((cur-nfp (current-nfp-tn vop)))
+               (when cur-nfp
+                 (move cur-nfp nfp)))
+             (move nsp-tn nsp)))
+
+(define-vop (current-stack-pointer)
+    (:results (res :scs (any-reg descriptor-reg)))
+  (:generator 1
+             (move res csp-tn)))
+
+(define-vop (current-binding-pointer)
+    (:results (res :scs (any-reg descriptor-reg)))
+  (:generator 1
+             (move res bsp-tn)))
+
+\f
+;;;; unwind block hackery:
+
+;;; Compute the address of the catch block from its TN, then store
+;;; into the block the current Fp, Env, Unwind-Protect, and the entry
+;;; PC.
+(define-vop (make-unwind-block)
+  (:args (tn))
+  (:info entry-label)
+  (:results (block :scs (any-reg)))
+  (:temporary (:scs (descriptor-reg)) temp)
+  (:temporary (:scs (non-descriptor-reg)) ndescr)
+  (:generator 22
+    (inst add block cfp-tn (* (tn-offset tn) n-word-bytes))
+    (load-symbol-value temp *current-unwind-protect-block*)
+    (storew temp block unwind-block-current-uwp-slot)
+    (storew cfp-tn block unwind-block-current-cont-slot)
+    (storew code-tn block unwind-block-current-code-slot)
+    (inst compute-lra-from-code temp code-tn entry-label ndescr)
+    (storew temp block catch-block-entry-pc-slot)))
+
+
+;;; Like Make-Unwind-Block, except that we also store in the specified tag, and
+;;; link the block into the Current-Catch list.
+(define-vop (make-catch-block)
+  (:args (tn)
+        (tag :scs (descriptor-reg)))
+  (:info entry-label)
+  (:results (block :scs (any-reg)))
+  (:temporary (:scs (descriptor-reg)) temp)
+  (:temporary (:scs (descriptor-reg) :target block :to (:result 0)) result)
+  (:temporary (:scs (non-descriptor-reg)) ndescr)
+  (:generator 44
+    (inst add result cfp-tn (* (tn-offset tn) n-word-bytes))
+    (load-symbol-value temp *current-unwind-protect-block*)
+    (storew temp result catch-block-current-uwp-slot)
+    (storew cfp-tn result catch-block-current-cont-slot)
+    (storew code-tn result catch-block-current-code-slot)
+    (inst compute-lra-from-code temp code-tn entry-label ndescr)
+    (storew temp result catch-block-entry-pc-slot)
+
+    (storew tag result catch-block-tag-slot)
+    (load-symbol-value temp *current-catch-block*)
+    (storew temp result catch-block-previous-catch-slot)
+    (store-symbol-value result *current-catch-block*)
+
+    (move block result)))
+
+
+;;; Just set the current unwind-protect to TN's address.  This instantiates an
+;;; unwind block as an unwind-protect.
+(define-vop (set-unwind-protect)
+  (:args (tn))
+  (:temporary (:scs (descriptor-reg)) new-uwp)
+  (:generator 7
+    (inst add new-uwp cfp-tn (* (tn-offset tn) n-word-bytes))
+    (store-symbol-value new-uwp *current-unwind-protect-block*)))
+
+
+(define-vop (unlink-catch-block)
+  (:temporary (:scs (any-reg)) block)
+  (:policy :fast-safe)
+  (:translate %catch-breakup)
+  (:generator 17
+    (load-symbol-value block *current-catch-block*)
+    (loadw block block catch-block-previous-catch-slot)
+    (store-symbol-value block *current-catch-block*)))
+
+(define-vop (unlink-unwind-protect)
+  (:temporary (:scs (any-reg)) block)
+  (:policy :fast-safe)
+  (:translate %unwind-protect-breakup)
+  (:generator 17
+    (load-symbol-value block *current-unwind-protect-block*)
+    (loadw block block unwind-block-current-uwp-slot)
+    (store-symbol-value block *current-unwind-protect-block*)))
+
+\f
+;;;; NLX entry VOPs:
+
+
+(define-vop (nlx-entry)
+  (:args (sp) ; Note: we can't list an sc-restriction, 'cause any load vops
+             ; would be inserted before the LRA.
+        (start)
+        (count))
+  (:results (values :more t))
+  (:temporary (:scs (descriptor-reg)) move-temp)
+  (:info label nvals)
+  (:save-p :force-to-stack)
+  (:vop-var vop)
+  (:generator 30
+    (emit-return-pc label)
+    (note-this-location vop :non-local-entry)
+    (cond ((zerop nvals))
+         ((= nvals 1)
+          (let ((no-values (gen-label)))
+            (inst cmp count)
+            (inst b :eq no-values)
+            (move (tn-ref-tn values) null-tn)
+            (loadw (tn-ref-tn values) start)
+            (emit-label no-values)))
+         (t
+          (collect ((defaults))
+            (inst subcc count (fixnumize 1))
+            (do ((i 0 (1+ i))
+                 (tn-ref values (tn-ref-across tn-ref)))
+                ((null tn-ref))
+              (let ((default-lab (gen-label))
+                    (tn (tn-ref-tn tn-ref)))
+                (defaults (cons default-lab tn))
+                
+                (inst b :lt default-lab)
+                (inst subcc count (fixnumize 1))
+                (sc-case tn
+                         ((descriptor-reg any-reg)
+                          (loadw tn start i))
+                         (control-stack
+                          (loadw move-temp start i)
+                          (store-stack-tn tn move-temp)))))
+            
+            (let ((defaulting-done (gen-label)))
+              
+              (emit-label defaulting-done)
+              
+              (assemble (*elsewhere*)
+                (dolist (def (defaults))
+                  (emit-label (car def))
+                  (let ((tn (cdr def)))
+                    (sc-case tn
+                             ((descriptor-reg any-reg)
+                              (move tn null-tn))
+                             (control-stack
+                              (store-stack-tn tn null-tn)))))
+                (inst b defaulting-done)
+                (inst nop))))))
+    (load-stack-tn csp-tn sp)))
+
+
+(define-vop (nlx-entry-multiple)
+  (:args (top :target result) (src) (count))
+  ;; Again, no SC restrictions for the args, 'cause the loading would
+  ;; happen before the entry label.
+  (:info label)
+  (:temporary (:scs (any-reg)) dst)
+  (:temporary (:scs (descriptor-reg)) temp)
+  (:results (result :scs (any-reg) :from (:argument 0))
+           (num :scs (any-reg) :from (:argument 0)))
+  (:save-p :force-to-stack)
+  (:vop-var vop)
+  (:generator 30
+    (emit-return-pc label)
+    (note-this-location vop :non-local-entry)
+    (let ((loop (gen-label))
+         (done (gen-label)))
+
+      ;; Setup results, and test for the zero value case.
+      (load-stack-tn result top)
+      (inst cmp count)
+      (inst b :eq done)
+      (inst li num 0)
+
+      ;; Compute dst as one slot down from result, because we inc the index
+      ;; before we use it.
+      (inst sub dst result 4)
+
+      ;; Copy stuff down the stack.
+      (emit-label loop)
+      (inst ld temp src num)
+      (inst add num (fixnumize 1))
+      (inst cmp num count)
+      (inst b :ne loop)
+      (inst st temp dst num)
+
+      ;; Reset the CSP.
+      (emit-label done)
+      (inst add csp-tn result num))))
+
+
+;;; This VOP is just to force the TNs used in the cleanup onto the stack.
+;;;
+(define-vop (uwp-entry)
+  (:info label)
+  (:save-p :force-to-stack)
+  (:results (block) (start) (count))
+  (:ignore block start count)
+  (:vop-var vop)
+  (:generator 0
+    (emit-return-pc label)
+    (note-this-location vop :non-local-entry)))
+
diff --git a/src/compiler/sparc/parms.lisp b/src/compiler/sparc/parms.lisp
new file mode 100644 (file)
index 0000000..51e3efd
--- /dev/null
@@ -0,0 +1,236 @@
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; Machine Architecture parameters:
+(eval-when (:compile-toplevel :load-toplevel :execute)
+
+(defconstant n-word-bits 32
+  #!+sb-doc
+  "Number of bits per word where a word holds one lisp descriptor.")
+
+(defconstant n-byte-bits 8
+  #!+sb-doc
+  "Number of bits per byte where a byte is the smallest addressable object.")
+
+(defconstant word-shift (1- (integer-length (/ n-word-bits n-byte-bits)))
+  #!+sb-doc
+  "Number of bits to shift between word addresses and byte addresses.")
+
+(defconstant n-word-bytes (/ n-word-bits n-byte-bits)
+  #!+sb-doc
+  "Number of bytes in a word.")
+
+;;; FIXME: The following three should probably be rationalized or at
+;;; least prefixed with n- where applicable
+(defconstant fixnum-tag-bits (1- n-lowtag-bits)
+  #!+sb-doc
+  "Number of tag bits used for a fixnum")
+
+(defconstant fixnum-tag-mask (1- (ash 1 fixnum-tag-bits))
+  #!+sb-doc
+  "Mask to get the fixnum tag")
+
+(defconstant positive-fixnum-bits (- n-word-bits fixnum-tag-bits 1)
+  #!+sb-doc
+  "Maximum number of bits in a positive fixnum")
+
+(defconstant float-sign-shift 31)
+
+(defconstant single-float-bias 126)
+(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp)
+(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp)
+(defconstant single-float-normal-exponent-min 1)
+(defconstant single-float-normal-exponent-max 254)
+(defconstant single-float-hidden-bit (ash 1 23))
+(defconstant single-float-trapping-nan-bit (ash 1 22))
+
+(defconstant double-float-bias 1022)
+(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp)
+(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp)
+(defconstant double-float-normal-exponent-min 1)
+(defconstant double-float-normal-exponent-max #x7FE)
+(defconstant double-float-hidden-bit (ash 1 20))
+(defconstant double-float-trapping-nan-bit (ash 1 19))
+
+;;; CMUCL COMMENT:
+;;;   X These values are for the x86 80 bit format and are no doubt
+;;;   incorrect for the sparc.
+;;; FIXME
+(defconstant long-float-bias 16382)
+(defconstant-eqx long-float-exponent-byte (byte 15 0) #'equalp)
+(defconstant-eqx long-float-significand-byte (byte 31 0) #'equalp)
+(defconstant long-float-normal-exponent-min 1)
+(defconstant long-float-normal-exponent-max #x7FFE)
+(defconstant long-float-hidden-bit (ash 1 31))
+(defconstant long-float-trapping-nan-bit (ash 1 30))
+
+(defconstant single-float-digits
+  (+ (byte-size single-float-significand-byte) 1))
+
+(defconstant double-float-digits
+  (+ (byte-size double-float-significand-byte) n-word-bits 1))
+
+;;; This looks wrong - CSR
+(defconstant long-float-digits
+  (+ (byte-size long-float-significand-byte) n-word-bits 1))
+
+(defconstant float-inexact-trap-bit (ash 1 0))
+(defconstant float-divide-by-zero-trap-bit (ash 1 1))
+(defconstant float-underflow-trap-bit (ash 1 2))
+(defconstant float-overflow-trap-bit (ash 1 3))
+(defconstant float-invalid-trap-bit (ash 1 4))
+
+(defconstant float-round-to-nearest 0)
+(defconstant float-round-to-zero 1)
+(defconstant float-round-to-positive 2)
+(defconstant float-round-to-negative 3)
+
+(defconstant-eqx float-rounding-mode (byte 2 30) #'equalp)       ; RD 
+(defconstant-eqx float-sticky-bits (byte 5 5) #'equalp)          ; aexc
+(defconstant-eqx float-traps-byte (byte 5 23) #'equalp)          ; TEM
+(defconstant-eqx float-exceptions-byte (byte 5 0) #'equalp)      ; cexc
+
+;;; According to the SPARC doc (as opposed to FPU doc), the fast mode
+;;; bit (EFM) is "reserved", and should always be zero.  However, for
+;;; sparc-V8 and sparc-V9, it appears to work, causing denormals to
+;;; be truncated to 0 silently.
+(defconstant float-fast-bit (ash 1 22))
+
+); eval-when
+
+;;; NUMBER-STACK-DISPLACEMENT
+;;;
+;;; The number of bytes reserved above the number stack pointer.  These
+;;; slots are required by architecture for a place to spill register windows.
+;;;
+;;; FIXME: Where is this used?
+(defconstant number-stack-displacement
+  (* 16 n-word-bytes))
+
+\f
+;;;; Description of the target address space.
+
+;;; Where to put the different spaces.  Must match the C code!
+#!+linux
+(progn
+  (defconstant read-only-space-start #x10000000)
+  (defconstant read-only-space-end #x15000000)
+
+  (defconstant static-space-start    #x28000000)
+  (defconstant static-space-end #x2c000000)
+
+  ;; From alpha/parms.lisp:
+  ;; this is used in PURIFY as part of a sloppy check to see if a pointer
+  ;; is in dynamic space.  Chocolate brownie for the first person to fix it
+  ;; -dan 20010502
+  (defconstant dynamic-space-start   #x30000000)
+  (defconstant dynamic-space-end     #x38000000)
+
+  (defconstant dynamic-0-space-start   #x30000000)
+  (defconstant dynamic-0-space-end     #x38000000)
+  
+  (defconstant dynamic-1-space-start   #x40000000)
+  (defconstant dynamic-1-space-end     #x48000000)
+
+  (defconstant control-stack-start   #x50000000)
+  (defconstant control-stack-end     #x51000000)
+
+  (defconstant binding-stack-start    #x60000000)
+  (defconstant binding-stack-end      #x61000000))
+
+#!+solaris ; maybe someday.
+(progn
+  (defparameter target-read-only-space-start #x10000000)
+  (defparameter target-static-space-start    #x28000000)
+  (defparameter target-dynamic-space-start   #x40000000))
+\f
+;;;; other random constants.
+
+(defenum (:suffix -trap :start 8)
+  halt
+  pending-interrupt
+  error
+  cerror
+  breakpoint
+  fun-end-breakpoint
+  after-breakpoint)
+
+(defenum (:prefix object-not- :suffix -trap :start 16)
+  list
+  instance)
+
+(defenum (:prefix trace-table-)
+  normal
+  call-site
+  fun-prologue
+  fun-epilogue)
+\f
+;;;; static symbols.
+
+;;; These symbols are loaded into static space directly after NIL so
+;;; that the system can compute their address by adding a constant
+;;; amount to NIL.
+;;;
+;;; The fdefn objects for the static functions are loaded into static
+;;; space directly after the static symbols.  That way, the raw-addr
+;;; can be loaded directly out of them by indirecting relative to NIL.
+;;;
+(defparameter *static-symbols*
+  '(t
+
+    ;; The C startup code must fill these in.
+    *posix-argv*
+    ;;lisp::lisp-environment-list
+    ;;lisp::lisp-command-line-list
+    sb!impl::*!initial-fdefn-objects*
+
+    ;; Functions that the C code needs to call
+    maybe-gc
+    sb!kernel::internal-error
+    sb!di::handle-breakpoint
+    sb!di::handle-fun-end-breakpoint
+
+    ;; Free Pointers.
+    *read-only-space-free-pointer*
+    *static-space-free-pointer*
+    *initial-dynamic-space-free-pointer*
+
+    ;; Things needed for non-local-exit.
+    *current-catch-block*
+    *current-unwind-protect-block*
+
+    ;; Interrupt Handling
+    *free-interrupt-context-index*
+    sb!unix::*interrupts-enabled*
+    sb!unix::*interrupt-pending*
+    ))
+
+(defparameter *static-funs*
+  '(length
+    two-arg-+ two-arg-- two-arg-* two-arg-/ two-arg-< two-arg-> two-arg-=
+    two-arg-<= two-arg->= two-arg-/= eql %negate
+    two-arg-and two-arg-ior two-arg-xor
+    two-arg-gcd two-arg-lcm
+    ))
+\f
+;;;; Assembler parameters:
+
+;;; The number of bits per element in the assemblers code vector.
+;;;
+(defparameter *assembly-unit-length* 8)
+
+\f
+;;;; Pseudo-atomic trap number
+;;; KLUDGE
+#!-linux
+(defconstant pseudo-atomic-trap 16)
+#!+linux
+(defconstant pseudo-atomic-trap #x40)
diff --git a/src/compiler/sparc/pred.lisp b/src/compiler/sparc/pred.lisp
new file mode 100644 (file)
index 0000000..4959638
--- /dev/null
@@ -0,0 +1,38 @@
+;;;; the VM definition of predicate VOPs for the Sparc
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; the Branch VOP.
+
+;;; The unconditional branch, emitted when we can't drop through to
+;;; the desired destination.  Dest is the continuation we transfer
+;;; control to.
+(define-vop (branch)
+  (:info dest)
+  (:generator 5
+    (inst b dest)
+    (inst nop)))
+\f
+;;;; conditional VOPs:
+
+(define-vop (if-eq)
+  (:args (x :scs (any-reg descriptor-reg zero null))
+        (y :scs (any-reg descriptor-reg zero null)))
+  (:conditional)
+  (:info target not-p)
+  (:policy :fast-safe)
+  (:translate eq)
+  (:generator 3
+    (inst cmp x y)
+    (inst b (if not-p :ne :eq) target)
+    (inst nop)))
+
diff --git a/src/compiler/sparc/sap.lisp b/src/compiler/sparc/sap.lisp
new file mode 100644 (file)
index 0000000..dbd232b
--- /dev/null
@@ -0,0 +1,304 @@
+;;;; the Alpha VM definition of SAP operations
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; moves and coercions:
+
+;;; Move a tagged SAP to an untagged representation.
+(define-vop (move-to-sap)
+  (:args (x :scs (descriptor-reg)))
+  (:results (y :scs (sap-reg)))
+  (:note "pointer to SAP coercion")
+  (:generator 1
+    (loadw y x sap-pointer-slot other-pointer-lowtag)))
+
+(define-move-vop move-to-sap :move
+  (descriptor-reg) (sap-reg))
+
+
+;;; Move an untagged SAP to a tagged representation.
+(define-vop (move-from-sap)
+  (:args (sap :scs (sap-reg) :to :save))
+  (:temporary (:scs (non-descriptor-reg)) ndescr)
+  (:results (res :scs (descriptor-reg)))
+  (:note "SAP to pointer coercion") 
+  (:generator 20
+    (with-fixed-allocation (res ndescr sap-widetag sap-size)
+      (storew sap res sap-pointer-slot other-pointer-lowtag))))
+
+(define-move-vop move-from-sap :move
+  (sap-reg) (descriptor-reg))
+
+
+;;; Move untagged SAP values.
+(define-vop (sap-move)
+  (:args (x :target y
+           :scs (sap-reg)
+           :load-if (not (location= x y))))
+  (:results (y :scs (sap-reg)
+              :load-if (not (location= x y))))
+  (:note "SAP move")
+  (:effects)
+  (:affected)
+  (:generator 0
+    (move y x)))
+
+(define-move-vop sap-move :move
+  (sap-reg) (sap-reg))
+
+
+;;; Move untagged SAP arguments/return-values.
+(define-vop (move-sap-arg)
+  (:args (x :target y
+           :scs (sap-reg))
+        (fp :scs (any-reg)
+            :load-if (not (sc-is y sap-reg))))
+  (:results (y))
+  (:note "SAP argument move")
+  (:generator 0
+    (sc-case y
+      (sap-reg
+       (move y x))
+      (sap-stack
+       (storew x fp (tn-offset y))))))
+
+(define-move-vop move-sap-arg :move-arg
+  (descriptor-reg sap-reg) (sap-reg))
+
+
+;;; Use standard MOVE-ARG + coercion to move an untagged SAP to a
+;;; descriptor passing location.
+(define-move-vop move-arg :move-arg
+  (sap-reg) (descriptor-reg))
+\f
+;;;; SAP-INT and INT-SAP
+
+(define-vop (sap-int)
+  (:args (sap :scs (sap-reg) :target int))
+  (:arg-types system-area-pointer)
+  (:results (int :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:translate sap-int)
+  (:policy :fast-safe)
+  (:generator 1
+    (move int sap)))
+
+(define-vop (int-sap)
+  (:args (int :scs (unsigned-reg) :target sap))
+  (:arg-types unsigned-num)
+  (:results (sap :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:translate int-sap)
+  (:policy :fast-safe)
+  (:generator 1
+    (move sap int)))
+\f
+;;;; POINTER+ and POINTER-
+
+(define-vop (pointer+)
+  (:translate sap+)
+  (:args (ptr :scs (sap-reg))
+        (offset :scs (signed-reg)))
+  (:arg-types system-area-pointer signed-num)
+  (:results (res :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:policy :fast-safe)
+  (:generator 2
+    (inst add res ptr offset)))
+
+(define-vop (pointer+-c)
+  (:translate sap+)
+  (:args (ptr :scs (sap-reg)))
+  (:info offset)
+  (:arg-types system-area-pointer (:constant (signed-byte 13)))
+  (:results (res :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:policy :fast-safe)
+  (:generator 1
+    (inst add res ptr offset)))
+
+(define-vop (pointer-)
+  (:translate sap-)
+  (:args (ptr1 :scs (sap-reg))
+        (ptr2 :scs (sap-reg)))
+  (:arg-types system-area-pointer system-area-pointer)
+  (:policy :fast-safe)
+  (:results (res :scs (signed-reg)))
+  (:result-types signed-num)
+  (:generator 1
+    (inst sub res ptr1 ptr2)))
+\f
+;;;; mumble-SYSTEM-REF and mumble-SYSTEM-SET
+
+(macrolet ((def-system-ref-and-set (ref-name set-name sc type size &optional signed)
+              (let ((ref-name-c (symbolicate ref-name "-C"))
+                    (set-name-c (symbolicate set-name "-C")))
+                `(progn
+                  (define-vop (,ref-name)
+                      (:translate ,ref-name)
+                    (:policy :fast-safe)
+                    (:args (sap :scs (sap-reg))
+                     (offset :scs (signed-reg)))
+                    (:arg-types system-area-pointer signed-num)
+                    (:results (result :scs (,sc)))
+                    (:result-types ,type)
+                    (:generator 5
+                     ,@(if (eql size :long-float)
+                           '((load-long-reg result sap offset t))
+                           `((inst ,(ecase size
+                                           (:byte (if signed 'ldsb 'ldub))
+                                           (:short (if signed 'ldsh 'lduh))
+                                           (:long 'ld)
+                                           (:single 'ldf)
+                                           (:double 'lddf))
+                              result sap offset)))))
+                  (define-vop (,ref-name-c)
+                      (:translate ,ref-name)
+                    (:policy :fast-safe)
+                    (:args (sap :scs (sap-reg)))
+                    (:arg-types system-area-pointer (:constant (signed-byte 13)))
+                    (:info offset)
+                    (:results (result :scs (,sc)))
+                    (:result-types ,type)
+                    (:generator 4
+                     ,@(if (eql size :long-float)
+                           '((load-long-reg result sap offset t))
+                           `((inst ,(ecase size
+                                           (:byte (if signed 'ldsb 'ldub))
+                                           (:short (if signed 'ldsh 'lduh))
+                                           (:long 'ld)
+                                           (:single 'ldf)
+                                           (:double 'lddf))
+                              result sap offset)))))
+                  (define-vop (,set-name)
+                      (:translate ,set-name)
+                    (:policy :fast-safe)
+                    (:args (sap :scs (sap-reg))
+                     (offset :scs (signed-reg))
+                     (value :scs (,sc) :target result))
+                    (:arg-types system-area-pointer signed-num ,type)
+                    (:results (result :scs (,sc)))
+                    (:result-types ,type)
+                    (:generator 5
+                     ,@(if (eql size :long-float)
+                           '((store-long-reg value sap offset t))
+                           `((inst ,(ecase size
+                                           (:byte 'stb)
+                                           (:short 'sth)
+                                           (:long 'st)
+                                           (:single 'stf)
+                                           (:double 'stdf))
+                              value sap offset)))
+                     (unless (location= result value)
+                       ,@(case size
+                               (:single
+                                '((inst fmovs result value)))
+                               (:double
+                                '((move-double-reg result value)))
+                               (:long-float
+                                '((move-long-reg result value)))
+                               (t
+                                '((inst move result value)))))))
+                  (define-vop (,set-name-c)
+                      (:translate ,set-name)
+                    (:policy :fast-safe)
+                    (:args (sap :scs (sap-reg))
+                     (value :scs (,sc) :target result))
+                    (:arg-types system-area-pointer (:constant (signed-byte 13)) ,type)
+                    (:info offset)
+                    (:results (result :scs (,sc)))
+                    (:result-types ,type)
+                    (:generator 4
+                     ,@(if (eql size :long-float)
+                           '((store-long-reg value sap offset t))
+                           `((inst ,(ecase size
+                                           (:byte 'stb)
+                                           (:short 'sth)
+                                           (:long 'st)
+                                           (:single 'stf)
+                                           (:double 'stdf))
+                              value sap offset)))
+                     (unless (location= result value)
+                       ,@(case size
+                               (:single
+                                '((inst fmovs result value)))
+                               (:double
+                                '((move-double-reg result value)))
+                               (:long-float
+                                '((move-long-reg result value)))
+                               (t
+                                '((inst move result value)))))))))))
+
+  (def-system-ref-and-set sap-ref-8 %set-sap-ref-8
+    unsigned-reg positive-fixnum :byte nil)
+  (def-system-ref-and-set signed-sap-ref-8 %set-signed-sap-ref-8
+    signed-reg tagged-num :byte t)
+  (def-system-ref-and-set sap-ref-16 %set-sap-ref-16
+    unsigned-reg positive-fixnum :short nil)
+  (def-system-ref-and-set signed-sap-ref-16 %set-signed-sap-ref-16
+    signed-reg tagged-num :short t)
+  (def-system-ref-and-set sap-ref-32 %set-sap-ref-32
+    unsigned-reg unsigned-num :long nil)
+  (def-system-ref-and-set signed-sap-ref-32 %set-signed-sap-ref-32
+    signed-reg signed-num :long t)
+  ;; FIXME
+  #+ignore
+  (def-system-ref-and-set sap-ref-64 %set-sap-ref-64
+    unsigned-reg unsigned-num :quad nil)
+  #+ignore
+  (def-system-ref-and-set signed-sap-ref-64 %set-signed-sap-ref-64
+    signed-reg signed-num :quad t)
+  (def-system-ref-and-set sap-ref-sap %set-sap-ref-sap
+    sap-reg system-area-pointer :long)
+  (def-system-ref-and-set sap-ref-single %set-sap-ref-single
+    single-reg single-float :single)
+  (def-system-ref-and-set sap-ref-double %set-sap-ref-double
+    double-reg double-float :double)
+  #!+long-float
+  (def-system-ref-and-set sap-ref-long %set-sap-ref-long
+    long-reg long-float :long-float)
+) ; MACROLET
+\f
+;;; noise to convert normal lisp data objects into SAPs.
+
+(define-vop (vector-sap)
+  (:translate vector-sap)
+  (:policy :fast-safe)
+  (:args (vector :scs (descriptor-reg)))
+  (:results (sap :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:generator 2
+    (inst add sap vector
+         (- (* vector-data-offset n-word-bytes) other-pointer-lowtag))))
+\f
+;;; Transforms for 64-bit SAP accessors.
+#+ignore
+(deftransform sap-ref-64 ((sap offset) (* *))
+  '(logior (ash (sap-ref-32 sap offset) 32)
+          (sap-ref-32 sap (+ offset 4))))
+
+#+ignore
+(deftransform signed-sap-ref-64 ((sap offset) (* *))
+  '(logior (ash (signed-sap-ref-32 sap offset) 32)
+          (sap-ref-32 sap (+ 4 offset))))
+
+#+ignore
+(deftransform %set-sap-ref-64 ((sap offset value) (* * *))
+  '(progn
+     (%set-sap-ref-32 sap offset (ash value -32))
+     (%set-sap-ref-32 sap (+ offset 4) (logand value #xffffffff))))
+
+#+ignore
+(deftransform %set-signed-sap-ref-64 ((sap offset value) (* * *))
+  '(progn
+     (%set-signed-sap-ref-32 sap offset (ash value -32))
+     (%set-sap-ref-32 sap (+ 4 offset) (logand value #xffffffff))))
diff --git a/src/compiler/sparc/show.lisp b/src/compiler/sparc/show.lisp
new file mode 100644 (file)
index 0000000..a4f99ae
--- /dev/null
@@ -0,0 +1,35 @@
+;;;; temporary printing utilities and similar noise
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+(define-vop (print)
+  (:args (object :scs (descriptor-reg any-reg) :target nl0))
+  (:results (result :scs (descriptor-reg)))
+  (:save-p t)
+  (:temporary (:sc any-reg :offset nl0-offset :from (:argument 0)) nl0)
+  (:temporary (:sc any-reg :offset cfunc-offset) cfunc)
+  (:temporary (:sc interior-reg :offset lip-offset) lip)
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)
+  (:vop-var vop)
+  (:generator 100
+    (let ((cur-nfp (current-nfp-tn vop)))
+      (when cur-nfp
+       (store-stack-tn nfp-save cur-nfp))
+      (move nl0 object)
+      (inst li cfunc (make-fixup (extern-alien-name "debug_print") :foreign))
+      (inst li temp (make-fixup (extern-alien-name "call_into_c") :foreign))
+      (inst jal lip temp)
+      (inst nop)
+      (when cur-nfp
+       (load-stack-tn cur-nfp nfp-save))
+      (move result nl0))))
diff --git a/src/compiler/sparc/static-fn.lisp b/src/compiler/sparc/static-fn.lisp
new file mode 100644 (file)
index 0000000..ec94e28
--- /dev/null
@@ -0,0 +1,142 @@
+;;;; VOPs and macro magic for calling static functions
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+(define-vop (static-fun-template)
+  (:save-p t)
+  (:policy :safe)
+  (:variant-vars symbol)
+  (:vop-var vop)
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:temporary (:scs (descriptor-reg)) move-temp)
+  (:temporary (:sc descriptor-reg :offset lra-offset) lra)
+  (:temporary (:scs (descriptor-reg)) func)
+  (:temporary (:sc any-reg :offset nargs-offset) nargs)
+  (:temporary (:sc any-reg :offset ocfp-offset) old-fp)
+  (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save))
+
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+
+(defun static-fun-template-name (num-args num-results)
+  (intern (format nil "~:@(~R-arg-~R-result-static-fun~)"
+                 num-args num-results)))
+
+(defun moves (dst src)
+  (collect ((moves))
+    (do ((dst dst (cdr dst))
+        (src src (cdr src)))
+       ((or (null dst) (null src)))
+      (moves `(move ,(car dst) ,(car src))))
+    (moves)))
+
+(defun static-fun-template-vop (num-args num-results)
+  (assert (and (<= num-args register-arg-count)
+              (<= num-results register-arg-count))
+         (num-args num-results)
+         "Either too many args (~W) or too many results (~W).  Max = ~W"
+         num-args num-results register-arg-count)
+  (let ((num-temps (max num-args num-results)))
+    (collect ((temp-names) (temps) (arg-names) (args) (result-names) (results))
+      (dotimes (i num-results)
+       (let ((result-name (intern (format nil "RESULT-~D" i))))
+         (result-names result-name)
+         (results `(,result-name :scs (any-reg descriptor-reg)))))
+      (dotimes (i num-temps)
+       (let ((temp-name (intern (format nil "TEMP-~D" i))))
+         (temp-names temp-name)
+         (temps `(:temporary (:sc descriptor-reg
+                              :offset ,(nth i *register-arg-offsets*)
+                              ,@(when (< i num-args)
+                                  `(:from (:argument ,i)))
+                              ,@(when (< i num-results)
+                                  `(:to (:result ,i)
+                                    :target ,(nth i (result-names)))))
+                             ,temp-name))))
+      (dotimes (i num-args)
+       (let ((arg-name (intern (format nil "ARG-~D" i))))
+         (arg-names arg-name)
+         (args `(,arg-name
+                 :scs (any-reg descriptor-reg)
+                 :target ,(nth i (temp-names))))))
+      `(define-vop (,(static-fun-template-name num-args num-results)
+                   static-fun-template)
+        (:args ,@(args))
+        ,@(temps)
+        (:results ,@(results))
+        (:generator ,(+ 50 num-args num-results)
+          (let ((lra-label (gen-label))
+                (cur-nfp (current-nfp-tn vop)))
+            ,@(moves (temp-names) (arg-names))
+            (inst ld func null-tn (static-fun-offset symbol))
+            (inst li nargs (fixnumize ,num-args))
+            (when cur-nfp
+              (store-stack-tn nfp-save cur-nfp))
+            (inst move old-fp cfp-tn)
+            (inst move cfp-tn csp-tn)
+            (inst compute-lra-from-code lra code-tn lra-label temp)
+            (note-this-location vop :call-site)
+            (inst j func (- (ash simple-fun-code-offset word-shift)
+                            fun-pointer-lowtag))
+            (inst move code-tn func)
+            (emit-return-pc lra-label)
+            ,(collect ((bindings) (links))
+               (do ((temp (temp-names) (cdr temp))
+                    (name 'values (gensym))
+                    (prev nil name)
+                    (i 0 (1+ i)))
+                   ((= i num-results))
+                 (bindings `(,name
+                             (make-tn-ref ,(car temp) nil)))
+                 (when prev
+                   (links `(setf (tn-ref-across ,prev) ,name))))
+               `(let ,(bindings)
+                  ,@(links)
+                  (default-unknown-values vop
+                      ,(if (zerop num-results) nil 'values)
+                      ,num-results move-temp temp lra-label)))
+            (when cur-nfp
+              (load-stack-tn cur-nfp nfp-save))
+            ,@(moves (result-names) (temp-names))))))))
+
+
+) ; EVAL-WHEN
+
+
+;;; FIXME! This looks like a candidate for a dotimes to
+;;; register-arg-count.
+(macrolet ((frob (num-args num-res)
+            (static-fun-template-vop (eval num-args) (eval num-res))))
+  (frob 0 1)
+  (frob 1 1)
+  (frob 2 1)
+  (frob 3 1)
+  (frob 4 1)
+  (frob 5 1))
+
+(defmacro define-static-fun (name args &key (results '(x)) translate
+                            policy cost arg-types result-types)
+  `(define-vop (,name
+               ,(static-fun-template-name (length args)
+                                          (length results)))
+     (:variant ',name)
+     (:note ,(format nil "static-fun ~@(~S~)" name))
+     ,@(when translate
+        `((:translate ,translate)))
+     ,@(when policy
+        `((:policy ,policy)))
+     ,@(when cost
+        `((:generator-cost ,cost)))
+     ,@(when arg-types
+        `((:arg-types ,@arg-types)))
+     ,@(when result-types
+        `((:result-types ,@result-types)))))
diff --git a/src/compiler/sparc/subprim.lisp b/src/compiler/sparc/subprim.lisp
new file mode 100644 (file)
index 0000000..4ff2127
--- /dev/null
@@ -0,0 +1,53 @@
+;;;; linkage information for standard static functions, and random vops
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; LENGTH
+(define-vop (length/list)
+  (:translate length)
+  (:args (object :scs (descriptor-reg) :target ptr))
+  (:arg-types list)
+  (:temporary (:scs (descriptor-reg) :from (:argument 0)) ptr)
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:temporary (:scs (any-reg) :type fixnum :to (:result 0) :target result)
+             count)
+  (:results (result :scs (any-reg descriptor-reg)))
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:generator 50
+    (let ((done (gen-label))
+         (loop (gen-label))
+         (not-list (generate-cerror-code vop object-not-list-error object)))
+      (move ptr object)
+      (move count zero-tn)
+
+      (emit-label loop)
+
+      (inst cmp ptr null-tn)
+      (inst b :eq done)
+      (inst nop)
+
+      (test-type ptr temp not-list t list-pointer-lowtag)
+
+      (loadw ptr ptr cons-cdr-slot list-pointer-lowtag)
+      (inst add count count (fixnumize 1))
+      (test-type ptr temp loop nil list-pointer-lowtag)
+
+      (cerror-call vop done object-not-list-error ptr)
+
+      (emit-label done)
+      (move result count))))
+       
+
+(define-static-fun length (object) :translate length)
+
diff --git a/src/compiler/sparc/system.lisp b/src/compiler/sparc/system.lisp
new file mode 100644 (file)
index 0000000..77ab3ea
--- /dev/null
@@ -0,0 +1,243 @@
+;;;; Sparc VM definitions of various system hacking operations
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; type frobbing VOPs
+
+(define-vop (lowtag-of)
+  (:translate lowtag-of)
+  (:policy :fast-safe)
+  (:args (object :scs (any-reg descriptor-reg)))
+  (:results (result :scs (unsigned-reg)))
+  (:result-types positive-fixnum)
+  (:generator 1
+    (inst and result object lowtag-mask)))
+
+(define-vop (widetag-of)
+  (:translate widetag-of)
+  (:policy :fast-safe)
+  (:args (object :scs (descriptor-reg) :to (:eval 1)))
+  (:results (result :scs (unsigned-reg) :from (:eval 0)))
+  (:result-types positive-fixnum)
+  (:generator 6
+    ;; Grab the lowtag.
+    (inst andcc result object lowtag-mask)
+    ;; Check for various pointer types.
+    (inst cmp result list-pointer-lowtag)
+    (inst b :eq done)
+    (inst cmp result other-pointer-lowtag)
+    (inst b :eq other-pointer)
+    (inst cmp result fun-pointer-lowtag)
+    (inst b :eq function-pointer)
+    (inst cmp result instance-pointer-lowtag)
+    (inst b :eq done)
+    ;; Okay, it is an immediate.  If fixnum, we want zero.  Otherwise,
+    ;; we want the low 8 bits.
+    (inst andcc zero-tn object #b11)
+    (inst b :eq done)
+    (inst li result 0)
+    ;; It wasn't a fixnum, so get the low 8 bits.
+    (inst b done)
+    (inst and result object widetag-mask)
+    
+    FUNCTION-POINTER
+    (inst b done)
+    (load-type result object (- fun-pointer-lowtag))
+
+    OTHER-POINTER
+    (load-type result object (- other-pointer-lowtag))
+
+    DONE))
+
+
+(define-vop (fun-subtype)
+  (:translate fun-subtype)
+  (:policy :fast-safe)
+  (:args (function :scs (descriptor-reg)))
+  (:results (result :scs (unsigned-reg)))
+  (:result-types positive-fixnum)
+  (:generator 6
+    (load-type result function (- fun-pointer-lowtag))))
+
+(define-vop (set-fun-subtype)
+  (:translate (setf fun-subtype))
+  (:policy :fast-safe)
+  (:args (type :scs (unsigned-reg) :target result)
+        (function :scs (descriptor-reg)))
+  (:arg-types positive-fixnum *)
+  (:results (result :scs (unsigned-reg)))
+  (:result-types positive-fixnum)
+  (:generator 6
+    ;; FIXME: I don't understand what this hardcoded 3 is doing
+    ;; here. -- CSR, 2002-02-08
+    (inst stb type function (- 3 fun-pointer-lowtag))
+    (move result type)))
+
+(define-vop (get-header-data)
+  (:translate get-header-data)
+  (:policy :fast-safe)
+  (:args (x :scs (descriptor-reg)))
+  (:results (res :scs (unsigned-reg)))
+  (:result-types positive-fixnum)
+  (:generator 6
+    (loadw res x 0 other-pointer-lowtag)
+    (inst srl res res n-widetag-bits)))
+
+(define-vop (get-closure-length)
+  (:translate get-closure-length)
+  (:policy :fast-safe)
+  (:args (x :scs (descriptor-reg)))
+  (:results (res :scs (unsigned-reg)))
+  (:result-types positive-fixnum)
+  (:generator 6
+    (loadw res x 0 fun-pointer-lowtag)
+    (inst srl res res n-widetag-bits)))
+
+(define-vop (set-header-data)
+  (:translate set-header-data)
+  (:policy :fast-safe)
+  (:args (x :scs (descriptor-reg) :target res)
+        (data :scs (any-reg immediate zero)))
+  (:arg-types * positive-fixnum)
+  (:results (res :scs (descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) t1 t2)
+  (:generator 6
+    (loadw t1 x 0 other-pointer-lowtag)
+    (inst and t1 widetag-mask)
+    (sc-case data
+      (any-reg
+       (inst sll t2 data (- n-widetag-bits 2))
+       (inst or t1 t2))
+      (immediate
+       (inst or t1 (ash (tn-value data) n-widetag-bits)))
+      (zero))
+    (storew t1 x 0 other-pointer-lowtag)
+    (move res x)))
+
+
+(define-vop (make-fixnum)
+  (:args (ptr :scs (any-reg descriptor-reg)))
+  (:results (res :scs (any-reg descriptor-reg)))
+  (:generator 1
+    ;; FIXME: CMUCL comment:
+    ;; Some code (the hash table code) depends on this returning a
+    ;; positive number so make sure it does.
+    (inst sll res ptr 3)
+    (inst srl res res 1)))
+
+(define-vop (make-other-immediate-type)
+  (:args (val :scs (any-reg descriptor-reg))
+        (type :scs (any-reg descriptor-reg immediate)
+              :target temp))
+  (:results (res :scs (any-reg descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:generator 2
+    (sc-case type
+      (immediate
+       (inst sll temp val n-widetag-bits)
+       (inst or res temp (tn-value type)))
+      (t
+       (inst sra temp type 2)
+       (inst sll res val (- n-widetag-bits 2))
+       (inst or res res temp)))))
+
+\f
+;;;; allocation
+
+(define-vop (dynamic-space-free-pointer)
+  (:results (int :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:translate dynamic-space-free-pointer)
+  (:policy :fast-safe)
+  (:generator 1
+    (move int alloc-tn)))
+
+(define-vop (binding-stack-pointer-sap)
+  (:results (int :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:translate binding-stack-pointer-sap)
+  (:policy :fast-safe)
+  (:generator 1
+    (move int bsp-tn)))
+
+(define-vop (control-stack-pointer-sap)
+  (:results (int :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:translate control-stack-pointer-sap)
+  (:policy :fast-safe)
+  (:generator 1
+    (move int csp-tn)))
+
+\f
+;;;; code object frobbing.
+
+(define-vop (code-instructions)
+  (:translate code-instructions)
+  (:policy :fast-safe)
+  (:args (code :scs (descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) ndescr)
+  (:results (sap :scs (sap-reg)))
+  (:result-types system-area-pointer)
+  (:generator 10
+    (loadw ndescr code 0 other-pointer-lowtag)
+    (inst srl ndescr n-widetag-bits)
+    (inst sll ndescr word-shift)
+    (inst sub ndescr other-pointer-lowtag)
+    (inst add sap code ndescr)))
+
+(define-vop (compute-fun)
+  (:args (code :scs (descriptor-reg))
+        (offset :scs (signed-reg unsigned-reg)))
+  (:arg-types * positive-fixnum)
+  (:results (func :scs (descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) ndescr)
+  (:generator 10
+    (loadw ndescr code 0 other-pointer-lowtag)
+    (inst srl ndescr n-widetag-bits)
+    (inst sll ndescr word-shift)
+    (inst add ndescr offset)
+    (inst add ndescr (- fun-pointer-lowtag other-pointer-lowtag))
+    (inst add func code ndescr)))
+
+
+\f
+;;;; other random VOPs.
+
+
+(defknown sb!unix::receive-pending-interrupt () (values))
+(define-vop (sb!unix::receive-pending-interrupt)
+  (:policy :fast-safe)
+  (:translate sb!unix::receive-pending-interrupt)
+  (:generator 1
+    (inst unimp pending-interrupt-trap)))
+
+
+(define-vop (halt)
+  (:generator 1
+    (inst unimp halt-trap)))
+
+
+\f
+;;;; dynamic VOP count collection support
+
+(define-vop (count-me)
+  (:args (count-vector :scs (descriptor-reg)))
+  (:info index)
+  (:temporary (:scs (non-descriptor-reg)) count)
+  (:generator 1
+    (let ((offset
+          (- (* (+ index vector-data-offset) n-word-bytes)
+             other-pointer-lowtag)))
+      (assert (typep offset '(signed-byte 13)))
+      (inst ld count count-vector offset)
+      (inst add count 1)
+      (inst st count count-vector offset))))
diff --git a/src/compiler/sparc/target-insts.lisp b/src/compiler/sparc/target-insts.lisp
new file mode 100644 (file)
index 0000000..422aa7e
--- /dev/null
@@ -0,0 +1,15 @@
+;;;; This file is for stuff which was in CMU CL's insts.lisp
+;;;; file, but which in the SBCL build process can't be compiled
+;;;; into code for the cross-compilation host.
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
diff --git a/src/compiler/sparc/type-vops.lisp b/src/compiler/sparc/type-vops.lisp
new file mode 100644 (file)
index 0000000..e9de8df
--- /dev/null
@@ -0,0 +1,542 @@
+;;;; type testing and checking VOPs for the Sparc VM
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; Simple type checking and testing:
+;;;
+;;; These types are represented by a single type code, so are easily
+;;; open-coded as a mask and compare.
+(define-vop (check-type)
+  (:args (value :target result :scs (any-reg descriptor-reg)))
+  (:results (result :scs (any-reg descriptor-reg)))
+  (:temporary (:scs (non-descriptor-reg)) temp)
+  (:vop-var vop)
+  (:save-p :compute-only))
+
+(define-vop (type-predicate)
+  (:args (value :scs (any-reg descriptor-reg)))
+  (:conditional)
+  (:info target not-p)
+  (:policy :fast-safe)
+  (:temporary (:scs (non-descriptor-reg)) temp))
+
+;;; moved to macros. FIXME.
+;;;(defun cost-to-test-types (type-codes)
+;;;  (+ (* 2 (length type-codes))
+;;;     (if (> (apply #'max type-codes) lowtag-limit) 7 2)))
+;;;
+;;;(defparameter immediate-types
+;;;  (list base-char-type unbound-marker-type))
+;;;
+;;;(defparameter function-header-types
+;;;  (list funcallable-instance-header-type
+;;;        byte-code-function-type byte-code-closure-type
+;;;        function-header-type closure-function-header-type
+;;;        closure-header-type))
+;;;
+;; FIXME: there's a canonicalize-headers in alpha/ and x86/
+
+(defmacro def-type-vops (pred-name check-name ptype error-code
+                        &rest type-codes)
+  ;;; FIXME: #+sb-xc-host?
+  (let ((cost (cost-to-test-types (mapcar #'eval type-codes))))
+    `(progn
+      ,@(when pred-name
+          `((define-vop (,pred-name type-predicate)
+              (:translate ,pred-name)
+              (:generator ,cost
+                (test-type value temp target not-p ,@type-codes)))))
+       ,@(when check-name
+          `((define-vop (,check-name check-type)
+              (:generator ,cost
+                (let ((err-lab
+                       (generate-error-code vop ,error-code value)))
+                  (test-type value temp err-lab t ,@type-codes)
+                  (move result value))))))
+       ,@(when ptype
+          `((primitive-type-vop ,check-name (:check) ,ptype))))))
+
+;;; This is a direct translation of the code in CMUCL
+;;; compiler/sparc/macros.lisp. Don't blame me if it doesn't work.
+
+;;; moved test-type back to macros.lisp, as other bits of code use it
+;;; too. FIXME.
+
+
+
+
+  
+;; Don't use this because it uses the deprecated taddcctv instruction.
+#+ignore
+(progn
+  (def-type-vops fixnump nil nil nil even-fixnum-lowtag odd-fixnum-lowtag)
+  (define-vop (check-fixnum check-type)
+      (:ignore temp)
+    (:generator 1
+               (inst taddcctv result value zero-tn)))
+  (primitive-type-vop check-fixnum (:check) fixnum))
+  
+;; This avoids the taddcctv instruction
+(def-type-vops fixnump check-fixnum fixnum object-not-fixnum-error
+              even-fixnum-lowtag odd-fixnum-lowtag)
+(def-type-vops functionp check-fun function
+              object-not-fun-error fun-pointer-lowtag)
+  
+  ;; The following encode the error type and register in the trap
+  ;; instruction, however this breaks on the later sparc Ultra.
+  #+ignore
+  (progn
+    (def-type-vops listp nil nil nil list-pointer-lowtag)
+    (define-vop (check-list check-type)
+       (:generator 3
+                   (inst and temp value lowtag-mask)
+                   (inst cmp temp list-pointer-lowtag)
+                   (inst t :ne (logior (ash (tn-offset value) 8) object-not-list-trap))
+                   (move result value)))
+    (primitive-type-vop check-list (:check) list)
+    
+    (def-type-vops %instancep nil nil nil instance-pointer-lowtag)
+    (define-vop (check-instance check-type)
+       (:generator 3
+                   (inst and temp value lowtag-mask)
+                   (inst cmp temp instance-pointer-lowtag)
+                   (inst t :ne (logior (ash (tn-offset value) 8) object-not-instance-trap))
+                   (move result value)))
+    (primitive-type-vop check-instance (:check) instance))
+
+  ;; These avoid the trap instruction.
+  (def-type-vops listp check-list list object-not-list-error
+  list-pointer-lowtag)
+  (def-type-vops %instancep check-instance instance object-not-instance-error
+  instance-pointer-lowtag)
+      
+  (def-type-vops bignump check-bignum bignum
+  object-not-bignum-error bignum-widetag)
+      
+  (def-type-vops ratiop check-ratio ratio
+  object-not-ratio-error ratio-widetag)
+      
+  (def-type-vops complexp check-complex complex object-not-complex-error
+  complex-widetag complex-single-float-widetag
+  complex-double-float-widetag #!+long-float complex-long-float-widetag)
+
+  (def-type-vops complex-rational-p check-complex-rational nil
+  object-not-complex-rational-error complex-widetag)
+
+  (def-type-vops complex-float-p check-complex-float nil
+  object-not-complex-float-error
+  complex-single-float-widetag complex-double-float-widetag
+  #!+long-float complex-long-float-widetag)
+
+  (def-type-vops complex-single-float-p check-complex-single-float
+  complex-single-float object-not-complex-single-float-error
+  complex-single-float-widetag)
+
+  (def-type-vops complex-double-float-p check-complex-double-float
+  complex-double-float object-not-complex-double-float-error
+  complex-double-float-widetag)
+
+  #!+long-float
+  (def-type-vops complex-long-float-p check-complex-long-float
+  complex-long-float object-not-complex-long-float-error
+  complex-long-float-widetag)
+
+  (def-type-vops single-float-p check-single-float single-float
+  object-not-single-float-error single-float-widetag)
+
+  (def-type-vops double-float-p check-double-float double-float
+  object-not-double-float-error double-float-widetag)
+
+  #!+long-float
+  (def-type-vops long-float-p check-long-float long-float
+  object-not-long-float-error long-float-widetag)
+
+  (def-type-vops simple-string-p check-simple-string simple-string
+  object-not-simple-string-error simple-string-widetag)
+
+  (def-type-vops simple-bit-vector-p check-simple-bit-vector simple-bit-vector
+  object-not-simple-bit-vector-error simple-bit-vector-widetag)
+      
+  (def-type-vops simple-vector-p check-simple-vector simple-vector
+  object-not-simple-vector-error simple-vector-widetag)
+      
+  (def-type-vops simple-array-unsigned-byte-2-p
+  check-simple-array-unsigned-byte-2
+  simple-array-unsigned-byte-2
+  object-not-simple-array-unsigned-byte-2-error
+  simple-array-unsigned-byte-2-widetag)
+      
+  (def-type-vops simple-array-unsigned-byte-4-p
+  check-simple-array-unsigned-byte-4
+  simple-array-unsigned-byte-4
+  object-not-simple-array-unsigned-byte-4-error
+  simple-array-unsigned-byte-4-widetag)
+
+  (def-type-vops simple-array-unsigned-byte-8-p
+  check-simple-array-unsigned-byte-8
+  simple-array-unsigned-byte-8
+  object-not-simple-array-unsigned-byte-8-error
+  simple-array-unsigned-byte-8-widetag)
+
+  (def-type-vops simple-array-unsigned-byte-16-p
+  check-simple-array-unsigned-byte-16
+  simple-array-unsigned-byte-16
+  object-not-simple-array-unsigned-byte-16-error
+  simple-array-unsigned-byte-16-widetag)
+
+  (def-type-vops simple-array-unsigned-byte-32-p
+  check-simple-array-unsigned-byte-32
+  simple-array-unsigned-byte-32
+  object-not-simple-array-unsigned-byte-32-error
+  simple-array-unsigned-byte-32-widetag)
+
+  (def-type-vops simple-array-signed-byte-8-p
+  check-simple-array-signed-byte-8
+  simple-array-signed-byte-8
+  object-not-simple-array-signed-byte-8-error
+  simple-array-signed-byte-8-widetag)
+
+  (def-type-vops simple-array-signed-byte-16-p
+  check-simple-array-signed-byte-16
+  simple-array-signed-byte-16
+  object-not-simple-array-signed-byte-16-error
+  simple-array-signed-byte-16-widetag)
+
+  (def-type-vops simple-array-signed-byte-30-p
+  check-simple-array-signed-byte-30
+  simple-array-signed-byte-30
+  object-not-simple-array-signed-byte-30-error
+  simple-array-signed-byte-30-widetag)
+
+  (def-type-vops simple-array-signed-byte-32-p
+  check-simple-array-signed-byte-32
+  simple-array-signed-byte-32
+  object-not-simple-array-signed-byte-32-error
+  simple-array-signed-byte-32-widetag)
+      
+  (def-type-vops simple-array-single-float-p check-simple-array-single-float
+  simple-array-single-float object-not-simple-array-single-float-error
+  simple-array-single-float-widetag)
+
+  (def-type-vops simple-array-double-float-p check-simple-array-double-float
+  simple-array-double-float object-not-simple-array-double-float-error
+  simple-array-double-float-widetag)
+
+  #!+long-float
+  (def-type-vops simple-array-long-float-p check-simple-array-long-float
+  simple-array-long-float object-not-simple-array-long-float-error
+  simple-array-long-float-widetag)
+      
+  (def-type-vops simple-array-complex-single-float-p
+  check-simple-array-complex-single-float
+  simple-array-complex-single-float
+  object-not-simple-array-complex-single-float-error
+  simple-array-complex-single-float-widetag)
+      
+  (def-type-vops simple-array-complex-double-float-p
+  check-simple-array-complex-double-float
+  simple-array-complex-double-float
+  object-not-simple-array-complex-double-float-error
+  simple-array-complex-double-float-widetag)
+      
+  #!+long-float
+  (def-type-vops simple-array-complex-long-float-p
+  check-simple-array-complex-long-float
+  simple-array-complex-long-float
+  object-not-simple-array-complex-long-float-error
+  simple-array-complex-long-float-widetag)
+
+  (def-type-vops base-char-p check-base-char base-char
+  object-not-base-char-error base-char-widetag)
+      
+  (def-type-vops system-area-pointer-p check-system-area-pointer
+  system-area-pointer object-not-sap-error sap-widetag)
+      
+  (def-type-vops weak-pointer-p check-weak-pointer weak-pointer
+  object-not-weak-pointer-error weak-pointer-widetag)
+  ;; FIXME
+#|       
+  (def-type-vops scavenger-hook-p nil nil nil
+  0)
+|#
+  (def-type-vops code-component-p nil nil nil
+  code-header-widetag)
+      
+  (def-type-vops lra-p nil nil nil
+  return-pc-header-widetag)
+
+  (def-type-vops fdefn-p nil nil nil
+  fdefn-widetag)
+
+  (def-type-vops funcallable-instance-p nil nil nil
+  funcallable-instance-header-widetag)
+      
+  (def-type-vops array-header-p nil nil nil
+  simple-array-widetag complex-string-widetag complex-bit-vector-widetag
+  complex-vector-widetag complex-array-widetag)
+
+  ;; This appears to have disappeared. FIXME -- CSR
+  (def-type-vops nil check-fun-or-symbol nil object-not-fun-or-symbol-error
+  fun-pointer-lowtag symbol-header-widetag)
+      
+  (def-type-vops stringp check-string nil object-not-string-error
+  simple-string-widetag complex-string-widetag)
+      
+  (def-type-vops bit-vector-p check-bit-vector nil object-not-bit-vector-error
+  simple-bit-vector-widetag complex-bit-vector-widetag)
+
+  (def-type-vops vectorp check-vector nil object-not-vector-error
+  simple-string-widetag simple-bit-vector-widetag simple-vector-widetag
+  simple-array-unsigned-byte-2-widetag simple-array-unsigned-byte-4-widetag
+  simple-array-unsigned-byte-8-widetag simple-array-unsigned-byte-16-widetag
+  simple-array-unsigned-byte-32-widetag
+  simple-array-signed-byte-8-widetag simple-array-signed-byte-16-widetag
+  simple-array-signed-byte-30-widetag simple-array-signed-byte-32-widetag
+  simple-array-single-float-widetag simple-array-double-float-widetag
+  #!+long-float simple-array-long-float-widetag
+  simple-array-complex-single-float-widetag
+  simple-array-complex-double-float-widetag
+  #!+long-float simple-array-complex-long-float-widetag
+  complex-string-widetag complex-bit-vector-widetag complex-vector-widetag)
+
+(def-type-vops complex-vector-p check-complex-vector nil object-not-complex-vector-error
+  complex-vector-widetag)
+
+  (def-type-vops simple-array-p check-simple-array nil object-not-simple-array-error
+  simple-array-widetag simple-string-widetag simple-bit-vector-widetag
+  simple-vector-widetag simple-array-unsigned-byte-2-widetag
+  simple-array-unsigned-byte-4-widetag simple-array-unsigned-byte-8-widetag
+  simple-array-unsigned-byte-16-widetag simple-array-unsigned-byte-32-widetag
+  simple-array-signed-byte-8-widetag simple-array-signed-byte-16-widetag
+  simple-array-signed-byte-30-widetag simple-array-signed-byte-32-widetag
+  simple-array-single-float-widetag simple-array-double-float-widetag
+  #!+long-float simple-array-long-float-widetag
+  simple-array-complex-single-float-widetag
+  simple-array-complex-double-float-widetag
+  #!+long-float simple-array-complex-long-float-widetag)
+      
+  (def-type-vops arrayp check-array nil object-not-array-error
+  simple-array-widetag simple-string-widetag simple-bit-vector-widetag
+  simple-vector-widetag simple-array-unsigned-byte-2-widetag
+  simple-array-unsigned-byte-4-widetag simple-array-unsigned-byte-8-widetag
+  simple-array-unsigned-byte-16-widetag simple-array-unsigned-byte-32-widetag
+  simple-array-signed-byte-8-widetag simple-array-signed-byte-16-widetag
+  simple-array-signed-byte-30-widetag simple-array-signed-byte-32-widetag
+  simple-array-single-float-widetag simple-array-double-float-widetag
+  #!+long-float simple-array-long-float-widetag
+  simple-array-complex-single-float-widetag
+  simple-array-complex-double-float-widetag
+  #!+long-float simple-array-complex-long-float-widetag
+  complex-string-widetag complex-bit-vector-widetag complex-vector-widetag
+  complex-array-widetag)
+      
+  (def-type-vops numberp check-number nil object-not-number-error
+  even-fixnum-lowtag odd-fixnum-lowtag bignum-widetag ratio-widetag
+  single-float-widetag double-float-widetag #!+long-float long-float-widetag
+  complex-widetag complex-single-float-widetag complex-double-float-widetag
+  #!+long-float complex-long-float-widetag)
+      
+  (def-type-vops rationalp check-rational nil object-not-rational-error
+  even-fixnum-lowtag odd-fixnum-lowtag ratio-widetag bignum-widetag)
+      
+  (def-type-vops integerp check-integer nil object-not-integer-error
+  even-fixnum-lowtag odd-fixnum-lowtag bignum-widetag)
+      
+  (def-type-vops floatp check-float nil object-not-float-error
+  single-float-widetag double-float-widetag #!+long-float long-float-widetag)
+      
+  (def-type-vops realp check-real nil object-not-real-error
+  even-fixnum-lowtag odd-fixnum-lowtag ratio-widetag bignum-widetag
+  single-float-widetag double-float-widetag #!+long-float long-float-widetag)
+
+  \f
+;;;; Other integer ranges.
+
+  ;; A (signed-byte 32) can be represented with either fixnum or a
+  ;; bignum with exactly one digit.
+
+  (define-vop (signed-byte-32-p type-predicate)
+  (:translate signed-byte-32-p)
+  (:generator 45
+             (let ((not-target (gen-label)))
+               (multiple-value-bind
+                     (yep nope)
+                   (if not-p
+                       (values not-target target)
+                       (values target not-target))
+                 (inst andcc zero-tn value #x3)
+                 (inst b :eq yep)
+                 (test-type value temp nope t other-pointer-lowtag)
+                 (loadw temp value 0 other-pointer-lowtag)
+                 (inst cmp temp (+ (ash 1 n-widetag-bits)
+                                   bignum-widetag))
+                 (inst b (if not-p :ne :eq) target)
+                 (inst nop)
+                 (emit-label not-target)))))
+
+  (define-vop (check-signed-byte-32 check-type)
+  (:generator 45
+             (let ((nope (generate-error-code vop object-not-signed-byte-32-error value))
+                   (yep (gen-label)))
+               (inst andcc temp value #x3)
+               (inst b :eq yep)
+               (test-type value temp nope t other-pointer-lowtag)
+               (loadw temp value 0 other-pointer-lowtag)
+               (inst cmp temp (+ (ash 1 n-widetag-bits) bignum-widetag))
+               (inst b :ne nope)
+               (inst nop)
+               (emit-label yep)
+               (move result value))))
+
+
+  ;; An (unsigned-byte 32) can be represented with either a
+  ;; positive fixnum, a bignum with exactly one positive digit, or
+  ;; a bignum with exactly two digits and the second digit all
+  ;; zeros.
+
+  (define-vop (unsigned-byte-32-p type-predicate)
+  (:translate unsigned-byte-32-p)
+  (:generator 45
+             (let ((not-target (gen-label))
+                   (single-word (gen-label))
+                   (fixnum (gen-label)))
+               (multiple-value-bind
+                     (yep nope)
+                   (if not-p
+                       (values not-target target)
+                       (values target not-target))
+                 ;; Is it a fixnum?
+                 (inst andcc temp value #x3)
+                 (inst b :eq fixnum)
+                 (inst cmp value)
+
+                 ;; If not, is it an other pointer?
+                 (test-type value temp nope t other-pointer-lowtag)
+                 ;; Get the header.
+                 (loadw temp value 0 other-pointer-lowtag)
+                 ;; Is it one?
+                 (inst cmp temp (+ (ash 1 n-widetag-bits) bignum-widetag))
+                 (inst b :eq single-word)
+                 ;; If it's other than two, we can't be an
+                 ;; (unsigned-byte 32)
+                 (inst cmp temp (+ (ash 2 n-widetag-bits) bignum-widetag))
+                 (inst b :ne nope)
+                 ;; Get the second digit.
+                 (loadw temp value (1+ bignum-digits-offset) other-pointer-lowtag)
+                 ;; All zeros, its an (unsigned-byte 32).
+                 (inst cmp temp)
+                 (inst b :eq yep)
+                 (inst nop)
+                 ;; Otherwise, it isn't.
+                 (inst b nope)
+                 (inst nop)
+                       
+                 (emit-label single-word)
+                 ;; Get the single digit.
+                 (loadw temp value bignum-digits-offset other-pointer-lowtag)
+                 (inst cmp temp)
+                       
+                 ;; positive implies (unsigned-byte 32).
+                 (emit-label fixnum)
+                 (inst b (if not-p :lt :ge) target)
+                 (inst nop)
+                       
+                 (emit-label not-target)))))     
+
+  (define-vop (check-unsigned-byte-32 check-type)
+  (:generator 45
+             (let ((nope
+                    (generate-error-code vop object-not-unsigned-byte-32-error value))
+                   (yep (gen-label))
+                   (fixnum (gen-label))
+                   (single-word (gen-label)))
+               ;; Is it a fixnum?
+               (inst andcc temp value #x3)
+               (inst b :eq fixnum)
+               (inst cmp value)
+                       
+               ;; If not, is it an other pointer?
+               (test-type value temp nope t other-pointer-lowtag)
+               ;; Get the number of digits.
+               (loadw temp value 0 other-pointer-lowtag)
+               ;; Is it one?
+               (inst cmp temp (+ (ash 1 n-widetag-bits) bignum-widetag))
+               (inst b :eq single-word)
+               ;; If it's other than two, we can't be an (unsigned-byte 32)
+               (inst cmp temp (+ (ash 2 n-widetag-bits) bignum-widetag))
+               (inst b :ne nope)
+               ;; Get the second digit.
+               (loadw temp value (1+ bignum-digits-offset) other-pointer-lowtag)
+               ;; All zeros, its an (unsigned-byte 32).
+               (inst cmp temp)
+               (inst b :eq yep)
+               ;; Otherwise, it isn't.
+               (inst b :ne nope)
+               (inst nop)
+                       
+               (emit-label single-word)
+               ;; Get the single digit.
+               (loadw temp value bignum-digits-offset other-pointer-lowtag)
+               ;; positive implies (unsigned-byte 32).
+               (inst cmp temp)
+                       
+               (emit-label fixnum)
+               (inst b :lt nope)
+               (inst nop)
+                       
+               (emit-label yep)
+               (move result value))))
+
+
+  \f
+;;;; List/symbol types:
+
+  ;; symbolp (or symbol (eq nil))
+  ;; consp (and list (not (eq nil)))
+      
+  (define-vop (symbolp type-predicate)
+  (:translate symbolp)
+  (:generator 12
+             (let* ((drop-thru (gen-label))
+                    (is-symbol-label (if not-p drop-thru target)))
+               (inst cmp value null-tn)
+               (inst b :eq is-symbol-label)
+               (test-type value temp target not-p symbol-header-widetag)
+               (emit-label drop-thru))))
+      
+  (define-vop (check-symbol check-type)
+  (:generator 12
+             (let ((drop-thru (gen-label))
+                   (error (generate-error-code vop object-not-symbol-error value)))
+               (inst cmp value null-tn)
+               (inst b :eq drop-thru)
+               (test-type value temp error t symbol-header-widetag)
+               (emit-label drop-thru)
+               (move result value))))
+      
+  (define-vop (consp type-predicate)
+  (:translate consp)
+  (:generator 8
+             (let* ((drop-thru (gen-label))
+                    (is-not-cons-label (if not-p target drop-thru)))
+               (inst cmp value null-tn)
+               (inst b :eq is-not-cons-label)
+               (test-type value temp target not-p list-pointer-lowtag)
+               (emit-label drop-thru))))
+      
+  (define-vop (check-cons check-type)
+  (:generator 8
+             (let ((error (generate-error-code vop object-not-cons-error value)))
+               (inst cmp value null-tn)
+               (inst b :eq error)
+               (test-type value temp error t list-pointer-lowtag)
+               (move result value))))
diff --git a/src/compiler/sparc/values.lisp b/src/compiler/sparc/values.lisp
new file mode 100644 (file)
index 0000000..1a83482
--- /dev/null
@@ -0,0 +1,117 @@
+;;;; the sparc implementation of unknown-values VOPs
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+
+(define-vop (reset-stack-pointer)
+  (:args (ptr :scs (any-reg)))
+  (:generator 1
+    (move csp-tn ptr)))
+
+
+;;; Push some values onto the stack, returning the start and number of
+;;; values pushed as results.  It is assumed that the Vals are wired
+;;; to the standard argument locations.  Nvals is the number of values
+;;; to push.
+;;;
+;;; The generator cost is pseudo-random.  We could get it right by
+;;; defining a bogus SC that reflects the costs of the
+;;; memory-to-memory moves for each operand, but this seems
+;;; unworthwhile.
+(define-vop (push-values)
+  (:args (vals :more t))
+  (:results (start :scs (any-reg) :from :load)
+           (count :scs (any-reg)))
+  (:info nvals)
+  (:temporary (:scs (descriptor-reg)) temp)
+  (:generator 20
+    (inst move start csp-tn)
+    (inst add csp-tn csp-tn (* nvals n-word-bytes))
+    (do ((val vals (tn-ref-across val))
+        (i 0 (1+ i)))
+       ((null val))
+      (let ((tn (tn-ref-tn val)))
+       (sc-case tn
+         (descriptor-reg
+          (storew tn start i))
+         (control-stack
+          (load-stack-tn temp tn)
+          (storew temp start i)))))
+    (inst li count (fixnumize nvals))))
+
+;;; Push a list of values on the stack, returning Start and Count as
+;;; used in unknown values continuations.
+(define-vop (values-list)
+  (:args (arg :scs (descriptor-reg) :target list))
+  (:arg-types list)
+  (:policy :fast-safe)
+  (:results (start :scs (any-reg))
+           (count :scs (any-reg)))
+  (:temporary (:scs (descriptor-reg) :type list :from (:argument 0)) list)
+  (:temporary (:scs (descriptor-reg)) temp)
+  (:temporary (:scs (non-descriptor-reg)) ndescr)
+  (:vop-var vop)
+  (:save-p :compute-only)
+  (:generator 0
+    (let ((loop (gen-label))
+         (done (gen-label)))
+
+      (move list arg)
+      (move start csp-tn)
+
+      (emit-label loop)
+      (inst cmp list null-tn)
+      (inst b :eq done)
+      (loadw temp list cons-car-slot list-pointer-lowtag)
+      (loadw list list cons-cdr-slot list-pointer-lowtag)
+      (inst add csp-tn csp-tn n-word-bytes)
+      (storew temp csp-tn -1)
+      (test-type list ndescr loop nil list-pointer-lowtag)
+      (error-call vop bogus-arg-to-values-list-error list)
+
+      (emit-label done)
+      (inst sub count csp-tn start))))
+
+
+
+;;; Copy the more arg block to the top of the stack so we can use them
+;;; as function arguments.
+(define-vop (%more-arg-values)
+  (:args (context :scs (descriptor-reg any-reg) :target src)
+        (skip :scs (any-reg zero immediate))
+        (num :scs (any-reg) :target count))
+  (:arg-types * positive-fixnum positive-fixnum)
+  (:temporary (:sc any-reg :from (:argument 0)) src)
+  (:temporary (:sc any-reg :from (:argument 2)) dst)
+  (:temporary (:sc descriptor-reg :from (:argument 1)) temp)
+  (:temporary (:sc any-reg) i)
+  (:results (start :scs (any-reg))
+           (count :scs (any-reg)))
+  (:generator 20
+    (sc-case skip
+      (zero
+       (move src context))
+      (immediate
+       (inst add src context (* (tn-value skip) n-word-bytes)))
+      (any-reg
+       (inst add src context skip)))
+    (inst orcc count zero-tn num)
+    (inst b :eq done)
+    (inst move start csp-tn)
+    (inst move dst csp-tn)
+    (inst add csp-tn count)
+    (inst move i count)
+    LOOP
+    (inst subcc i 4)
+    (inst ld temp src i)
+    (inst b :ne loop)
+    (inst st temp dst i)
+    DONE))
diff --git a/src/compiler/sparc/vm.lisp b/src/compiler/sparc/vm.lisp
new file mode 100644 (file)
index 0000000..6c95405
--- /dev/null
@@ -0,0 +1,375 @@
+;;;; miscellaneous VM definition noise for the Sparc
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!VM")
+\f
+;;;; Define the registers
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+  (defvar *register-names* (make-array 32 :initial-element nil)))
+
+(macrolet ((defreg (name offset)
+              (let ((offset-sym (symbolicate name "-OFFSET")))
+                `(eval-when (:compile-toplevel :load-toplevel :execute)
+                  (defconstant ,offset-sym ,offset)
+                  (setf (svref *register-names* ,offset-sym)
+                       ,(symbol-name name)))))
+
+          (defregset (name &rest regs)
+               `(eval-when (:compile-toplevel :load-toplevel :execute)
+                 (defparameter ,name
+                   (list ,@(mapcar (lambda (name)
+                                     (symbolicate name "-OFFSET"))
+                                   regs))))))
+  ;; "c.f. src/runtime/sparc-lispregs.h
+
+  ;; Globals.  These are difficult to extract from a sigcontext.
+  (defreg zero 0)                              ; %g0
+  (defreg alloc 1)                             ; %g1
+  (defreg null 2)                              ; %g2
+  (defreg csp 3)                               ; %g3
+  (defreg cfp 4)                               ; %g4
+  (defreg bsp 5)                               ; %g5
+  ;; %g6 and %g7 are supposed to be reserved for the system.
+
+  ;; Outs.  These get clobbered when we call into C.
+  (defreg nl0 8)                               ; %o0
+  (defreg nl1 9)                               ; %o1
+  (defreg nl2 10)                              ; %o2
+  (defreg nl3 11)                              ; %o3
+  (defreg nl4 12)                              ; %o4
+  (defreg nl5 13)                              ; %o5
+  (defreg nsp 14)                              ; %o6
+  (defreg nargs 15)                            ; %o7
+
+  ;; Locals.  These are preserved when we call into C.
+  (defreg a0 16)                               ; %l0
+  (defreg a1 17)                               ; %l1
+  (defreg a2 18)                               ; %l2
+  (defreg a3 19)                               ; %l3
+  (defreg a4 20)                               ; %l4
+  (defreg a5 21)                               ; %l5
+  (defreg ocfp 22)                             ; %l6
+  (defreg lra 23)                              ; %l7
+
+  ;; Ins.  These are preserved just like locals.
+  (defreg cname 24)                            ; %i0
+  (defreg lexenv 25)                           ; %i1
+  (defreg l0 26)                               ; %i2
+  (defreg nfp 27)                              ; %i3
+  (defreg cfunc 28)                            ; %i4
+  (defreg code 29)                             ; %i5
+  ;; we can't touch reg 30 if we ever want to return
+  (defreg lip 31)                              ; %i7
+
+  (defregset non-descriptor-regs
+      nl0 nl1 nl2 nl3 nl4 nl5 cfunc nargs nfp)
+  
+  (defregset descriptor-regs
+      a0 a1 a2 a3 a4 a5 ocfp lra cname lexenv l0)
+
+  (defregset *register-arg-offsets*
+      a0 a1 a2 a3 a4 a5))
+\f
+;;;; SB and SC definition:
+
+(define-storage-base registers :finite :size 32)
+(define-storage-base float-registers :finite :size 64)
+(define-storage-base control-stack :unbounded :size 8)
+(define-storage-base non-descriptor-stack :unbounded :size 0)
+(define-storage-base constant :non-packed)
+(define-storage-base immediate-constant :non-packed)
+
+;;; Handy macro so we don't have to keep changing all the numbers whenever
+;;; we insert a new storage class.
+;;; 
+;;; FIXME: This macro is not needed in the runtime target.
+(defmacro define-storage-classes (&rest classes)
+  (do ((forms (list 'progn)
+             (let* ((class (car classes))
+                    (sc-name (car class))
+                    (constant-name (intern (concatenate 'simple-string
+                                                        (string sc-name)
+                                                        "-SC-NUMBER"))))
+               (list* `(define-storage-class ,sc-name ,index
+                         ,@(cdr class))
+                      `(defconstant ,constant-name ,index)
+                       ;; (The CMU CL version of this macro did
+                       ;;   `(EXPORT ',CONSTANT-NAME)
+                       ;; here, but in SBCL we try to have package
+                       ;; structure described statically in one
+                       ;; master source file, instead of building it
+                       ;; dynamically by letting all the system code
+                       ;; modify it as the system boots.)
+                      forms)))
+       (index 0 (1+ index))
+       (classes classes (cdr classes)))
+      ((null classes)
+       (nreverse forms))))
+
+;;; see comment in ../x86/vm.lisp.  The value of 7 was taken from
+;;; vm:catch-block-size in a cmucl that I happened to have around
+;;; and seems to be working so far    -dan
+;;;
+;;; arbitrarily taken for alpha, too. - Christophe
+(defconstant sb!vm::kludge-nondeterministic-catch-block-size 7)
+
+(define-storage-classes
+
+  ;; Non-immediate contstants in the constant pool
+  (constant constant)
+
+  ;; ZERO and NULL are in registers.
+  (zero immediate-constant)
+  (null immediate-constant)
+
+  ;; Anything else that can be an immediate.
+  (immediate immediate-constant)
+
+
+  ;; **** The stacks.
+
+  ;; The control stack.  (Scanned by GC)
+  (control-stack control-stack)
+
+  ;; The non-descriptor stacks.
+  (signed-stack non-descriptor-stack) ; (signed-byte 32)
+  (unsigned-stack non-descriptor-stack) ; (unsigned-byte 32)
+  (base-char-stack non-descriptor-stack) ; non-descriptor characters.
+  (sap-stack non-descriptor-stack) ; System area pointers.
+  (single-stack non-descriptor-stack) ; single-floats
+  (double-stack non-descriptor-stack
+               :element-size 2 :alignment 2) ; double floats.
+  #!+long-float
+  (long-stack non-descriptor-stack :element-size 4 :alignment 4) ; long floats.
+  ;; complex-single-floats
+  (complex-single-stack non-descriptor-stack :element-size 2)
+  ;; complex-double-floats.
+  (complex-double-stack non-descriptor-stack :element-size 4 :alignment 2)
+  #!+long-float
+  ;; complex-long-floats.
+  (complex-long-stack non-descriptor-stack :element-size 8 :alignment 4)
+
+
+  ;; **** Things that can go in the integer registers.
+
+  ;; Immediate descriptor objects.  Don't have to be seen by GC, but nothing
+  ;; bad will happen if they are.  (fixnums, characters, header values, etc).
+  (any-reg
+   registers
+   :locations #.(append non-descriptor-regs descriptor-regs)
+   :constant-scs (zero immediate)
+   :save-p t
+   :alternate-scs (control-stack))
+
+  ;; Pointer descriptor objects.  Must be seen by GC.
+  (descriptor-reg registers
+   :locations #.descriptor-regs
+   :constant-scs (constant null immediate)
+   :save-p t
+   :alternate-scs (control-stack))
+
+  ;; Non-Descriptor characters
+  (base-char-reg registers
+   :locations #.non-descriptor-regs
+   :constant-scs (immediate)
+   :save-p t
+   :alternate-scs (base-char-stack))
+
+  ;; Non-Descriptor SAP's (arbitrary pointers into address space)
+  (sap-reg registers
+   :locations #.non-descriptor-regs
+   :constant-scs (immediate)
+   :save-p t
+   :alternate-scs (sap-stack))
+
+  ;; Non-Descriptor (signed or unsigned) numbers.
+  (signed-reg registers
+   :locations #.non-descriptor-regs
+   :constant-scs (zero immediate)
+   :save-p t
+   :alternate-scs (signed-stack))
+  (unsigned-reg registers
+   :locations #.non-descriptor-regs
+   :constant-scs (zero immediate)
+   :save-p t
+   :alternate-scs (unsigned-stack))
+
+  ;; Random objects that must not be seen by GC.  Used only as temporaries.
+  (non-descriptor-reg registers
+   :locations #.non-descriptor-regs)
+
+  ;; Pointers to the interior of objects.  Used only as an temporary.
+  (interior-reg registers
+   :locations (#.lip-offset))
+
+
+  ;; **** Things that can go in the floating point registers.
+
+  ;; Non-Descriptor single-floats.
+  (single-reg float-registers
+   :locations #.(loop for i from 0 to 31 collect i)
+   :reserve-locations (28 29 30 31)
+   :constant-scs ()
+   :save-p t
+   :alternate-scs (single-stack))
+
+  ;; Non-Descriptor double-floats.
+  (double-reg float-registers
+   :locations #.(loop for i from 0 to #!-sparc-64 31 #!+sparc-64 63
+                     by 2 collect i)
+   :element-size 2 :alignment 2
+   :reserve-locations (28 30)
+   :constant-scs ()
+   :save-p t
+   :alternate-scs (double-stack))
+
+  ;; Non-Descriptor double-floats.
+  #!+long-float
+  (long-reg float-registers
+   :locations #.(loop for i from 0 to #!-sparc-64 31 #!+sparc-64 63
+                     by 4 collect i)
+   :element-size 4 :alignment 4
+   :reserve-locations (28)
+   :constant-scs ()
+   :save-p t
+   :alternate-scs (long-stack))
+
+  (complex-single-reg float-registers
+   :locations #.(loop for i from 0 to 31 by 2 collect i)
+   :element-size 2 :alignment 2
+   :reserve-locations (28 30)
+   :constant-scs ()
+   :save-p t
+   :alternate-scs (complex-single-stack))
+
+  (complex-double-reg float-registers
+   :locations #.(loop for i from 0 to #!-sparc-64 31 #!+sparc-64 63
+                     by 4 collect i)
+   :element-size 4 :alignment 4
+   :reserve-locations (28)
+   :constant-scs ()
+   :save-p t
+   :alternate-scs (complex-double-stack))
+
+  #!+long-float
+  (complex-long-reg float-registers
+   :locations #.(loop for i from 0 to #!-sparc-64 31 #!+sparc-64 63
+                     by 8 collect i)
+   :element-size 8 :alignment 8
+   :constant-scs ()
+   :save-p t
+   :alternate-scs (complex-long-stack))
+
+
+  ;; A catch or unwind block.
+  (catch-block control-stack :element-size sb!vm::kludge-nondeterministic-catch-block-size))
+
+
+\f
+;;;; Make some random tns for important registers.
+
+(macrolet ((defregtn (name sc)
+              (let ((offset-sym (symbolicate name "-OFFSET"))
+                    (tn-sym (symbolicate name "-TN")))
+                `(defparameter ,tn-sym
+                  (make-random-tn :kind :normal
+                   :sc (sc-or-lose ',sc)
+                   :offset ,offset-sym)))))
+  (defregtn zero any-reg)
+  (defregtn null descriptor-reg)
+  (defregtn code descriptor-reg)
+  (defregtn alloc any-reg)
+  
+  (defregtn nargs any-reg)
+  (defregtn bsp any-reg)
+  (defregtn csp any-reg)
+  (defregtn cfp any-reg)
+  (defregtn ocfp any-reg)
+  (defregtn nsp any-reg))
+
+
+\f
+;;; If value can be represented as an immediate constant, then return the
+;;; appropriate SC number, otherwise return NIL.
+(!def-vm-support-routine immediate-constant-sc (value)
+  (typecase value
+    ((integer 0 0)
+     (sc-number-or-lose 'zero))
+    (null
+     (sc-number-or-lose 'null))
+    ((or fixnum system-area-pointer character)
+     (sc-number-or-lose 'immediate))
+    (symbol
+     (if (static-symbol-p value)
+        (sc-number-or-lose 'immediate)
+        nil))))
+
+\f
+;;;; function call parameters
+
+;;; the SC numbers for register and stack arguments/return values.
+(defconstant register-arg-scn (meta-sc-number-or-lose 'descriptor-reg))
+(defconstant immediate-arg-scn (meta-sc-number-or-lose 'any-reg))
+(defconstant control-stack-arg-scn (meta-sc-number-or-lose 'control-stack))
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+
+  ;; offsets of special stack frame locations
+  (defconstant ocfp-save-offset 0)
+  (defconstant lra-save-offset 1)
+  (defconstant nfp-save-offset 2)
+
+  ;; the number of arguments/return values passed in registers.
+  ;;
+  (defconstant register-arg-count 6)
+
+  ;; names to use for the argument registers.
+  ;; 
+  (defparameter register-arg-names '(a0 a1 a2 a3 a4 a5))
+); eval-when (:compile-toplevel :load-toplevel :execute)
+
+
+;;; a list of TN's describing the register arguments.
+(defparameter *register-arg-tns*
+  (mapcar (lambda (n)
+           (make-random-tn :kind :normal
+                             :sc (sc-or-lose 'descriptor-reg)
+                             :offset n))
+         *register-arg-offsets*))
+
+;;; This is used by the debugger.
+(defconstant single-value-return-byte-offset 8)
+
+\f
+;;; This function is called by debug output routines that want a
+;;; pretty name for a TN's location. It returns a thing that can be
+;;; printed with PRINC.
+(!def-vm-support-routine location-print-name (tn)
+  (declare (type tn tn)) ; FIXME: commented out on alpha
+  (let ((sb (sb-name (sc-sb (tn-sc tn))))
+       (offset (tn-offset tn)))
+    (ecase sb
+      (registers (or (svref *register-names* offset)
+                    (format nil "R~D" offset)))
+      (float-registers (format nil "F~D" offset))
+      (control-stack (format nil "CS~D" offset))
+      (non-descriptor-stack (format nil "NS~D" offset))
+      (constant (format nil "Const~D" offset))
+      (immediate-constant "Immed"))))
+
+\f
+;;; The loader uses this to convert alien names to the form they
+;;; occure in the symbol table (for example, prepending an
+;;; underscore).  On the SPARC, we don't prepend an underscore.
+(defun extern-alien-name (name)
+  (declare (type simple-base-string name))
+  (concatenate 'string #+nil "_" name))
diff --git a/src/runtime/Config.sparc-linux b/src/runtime/Config.sparc-linux
new file mode 100644 (file)
index 0000000..bf3f108
--- /dev/null
@@ -0,0 +1,27 @@
+# This software is part of the SBCL system. See the README file for
+# more information.
+#
+# This software is derived from the CMU CL system, which was
+# written at Carnegie Mellon University and released into the
+# public domain. The software is in the public domain and is
+# provided with absolutely no warranty. See the COPYING and CREDITS
+# files for more information.
+
+# -mcpu=pca56 makes _my_ alpha go fast, I'm told.  Yours may do something 
+# else.
+CFLAGS = -g -Wall -Dsparc
+ASFLAGS = -g -Wall -Dsparc
+LD = ld 
+LINKFLAGS = -v -g 
+NM = nm -p
+
+ASSEM_SRC = sparc-assem.S 
+ARCH_SRC = sparc-arch.c undefineds.c 
+#ARCH_SRC = sparc-arch.c ldso-stubs.S
+
+OS_SRC = linux-os.c  sparc-linux-os.c os-common.c 
+LINKFLAGS+=-static 
+#LINKFLAGS+=-rdynamic
+OS_LIBS= -ldl
+
+GC_SRC= gc.c
index 5abdf24..6a41dcb 100644 (file)
@@ -38,11 +38,11 @@ extern size_t os_vm_page_size;
 void
 arch_init(void)
 {
 void
 arch_init(void)
 {
-    /* This must be called _after_ os_init, so we know what the page
-     * size is. */
-    if(mmap((os_vm_address_t) call_into_lisp_LRA_page,os_vm_page_size,
-           OS_VM_PROT_ALL,MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,-1,0)
-       == (os_vm_address_t) -1)
+    /* This must be called _after_ os_init(), so that we know what the
+     * page size is. */
+    if (mmap((os_vm_address_t) call_into_lisp_LRA_page,os_vm_page_size,
+            OS_VM_PROT_ALL,MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,-1,0)
+       == (os_vm_address_t) -1)
        perror("mmap");
     
     /* call_into_lisp_LRA is a collection of trampolines written in asm -
        perror("mmap");
     
     /* call_into_lisp_LRA is a collection of trampolines written in asm -
@@ -67,21 +67,21 @@ arch_get_bad_addr (int sig, siginfo_t *code, os_context_t *context)
        sig, code, context); */
     pc= (unsigned int *)(*os_context_pc_addr(context));
 
        sig, code, context); */
     pc= (unsigned int *)(*os_context_pc_addr(context));
 
-    if(((unsigned long)pc) & 3) {
+    if (((unsigned long)pc) & 3) {
        return NULL;            /* In what case would pc be unaligned?? */
     }
 
        return NULL;            /* In what case would pc be unaligned?? */
     }
 
-    if( (pc < READ_ONLY_SPACE_START ||
-        pc >= READ_ONLY_SPACE_START+READ_ONLY_SPACE_SIZE) && 
-       (pc < current_dynamic_space ||
-        pc >= current_dynamic_space + DYNAMIC_SPACE_SIZE))
+    if ( (pc < READ_ONLY_SPACE_START ||
+         pc >= READ_ONLY_SPACE_START+READ_ONLY_SPACE_SIZE) && 
+        (pc < current_dynamic_space ||
+         pc >= current_dynamic_space + DYNAMIC_SPACE_SIZE))
        return NULL;
 
     badinst = *pc;
 
        return NULL;
 
     badinst = *pc;
 
-    if(((badinst>>27)!=0x16)      /* STL or STQ */
-       && ((badinst>>27)!=0x13))  /* STS or STT */
-       return NULL;                /* Otherwise forget about address. */
+    if (((badinst>>27)!=0x16)  /* STL or STQ */
+       && ((badinst>>27)!=0x13)) /* STS or STT */
+       return NULL;            /* Otherwise forget about address. */
   
     return (os_vm_address_t)
        (*os_context_register_addr(context,((badinst>>16)&0x1f))
   
     return (os_vm_address_t)
        (*os_context_register_addr(context,((badinst>>16)&0x1f))
@@ -182,50 +182,50 @@ emulate_branch(os_context_t *context,unsigned long orig_inst)
        branch = 1;
        break;
     case 0x31: /* fbeq */
        branch = 1;
        break;
     case 0x31: /* fbeq */
-       if(*(os_context_fpregister_addr(context,reg_a))==0) branch = 1;
+       if (*(os_context_float_register_addr(context,reg_a))==0) branch = 1;
        break;
     case 0x32: /* fblt */
        break;
     case 0x32: /* fblt */
-       if(*os_context_fpregister_addr(context,reg_a)<0) branch = 1;
+       if (*os_context_float_register_addr(context,reg_a)<0) branch = 1;
        break;
     case 0x33: /* fble */
        break;
     case 0x33: /* fble */
-       if(*os_context_fpregister_addr(context,reg_a)<=0) branch = 1;
+       if (*os_context_float_register_addr(context,reg_a)<=0) branch = 1;
        break;
     case 0x34: /* bsr */
        *os_context_register_addr(context,reg_a)=*os_context_pc_addr(context);
        branch = 1;
        break;
     case 0x35: /* fbne */
        break;
     case 0x34: /* bsr */
        *os_context_register_addr(context,reg_a)=*os_context_pc_addr(context);
        branch = 1;
        break;
     case 0x35: /* fbne */
-       if(*os_context_register_addr(context,reg_a)!=0) branch = 1;
+       if (*os_context_register_addr(context,reg_a)!=0) branch = 1;
        break;
     case 0x36: /* fbge */
        break;
     case 0x36: /* fbge */
-       if(*os_context_fpregister_addr(context,reg_a)>=0) branch = 1;
+       if (*os_context_float_register_addr(context,reg_a)>=0) branch = 1;
        break;
     case 0x37: /* fbgt */
        break;
     case 0x37: /* fbgt */
-       if(*os_context_fpregister_addr(context,reg_a)>0) branch = 1;
+       if (*os_context_float_register_addr(context,reg_a)>0) branch = 1;
        break;
     case 0x38: /* blbc */
        break;
     case 0x38: /* blbc */
-       if((*os_context_register_addr(context,reg_a)&1) == 0) branch = 1;
+       if ((*os_context_register_addr(context,reg_a)&1) == 0) branch = 1;
        break;
     case 0x39: /* beq */
        break;
     case 0x39: /* beq */
-       if(*os_context_register_addr(context,reg_a)==0) branch = 1;
+       if (*os_context_register_addr(context,reg_a)==0) branch = 1;
        break;
     case 0x3a: /* blt */
        break;
     case 0x3a: /* blt */
-       if(*os_context_register_addr(context,reg_a)<0) branch = 1;
+       if (*os_context_register_addr(context,reg_a)<0) branch = 1;
        break;
     case 0x3b: /* ble */
        break;
     case 0x3b: /* ble */
-       if(*os_context_register_addr(context,reg_a)<=0) branch = 1;
+       if (*os_context_register_addr(context,reg_a)<=0) branch = 1;
        break;
     case 0x3c: /* blbs */
        break;
     case 0x3c: /* blbs */
-       if((*os_context_register_addr(context,reg_a)&1)!=0) branch = 1;
+       if ((*os_context_register_addr(context,reg_a)&1)!=0) branch = 1;
        break;
     case 0x3d: /* bne */
        break;
     case 0x3d: /* bne */
-       if(*os_context_register_addr(context,reg_a)!=0) branch = 1;
+       if (*os_context_register_addr(context,reg_a)!=0) branch = 1;
        break;
     case 0x3e: /* bge */
        break;
     case 0x3e: /* bge */
-       if(*os_context_register_addr(context,reg_a)>=0) branch = 1;
+       if (*os_context_register_addr(context,reg_a)>=0) branch = 1;
        break;
     case 0x3f: /* bgt */
        break;
     case 0x3f: /* bgt */
-       if(*os_context_register_addr(context,reg_a)>0) branch = 1;
+       if (*os_context_register_addr(context,reg_a)>0) branch = 1;
        break;
     }
     if (branch)
        break;
     }
     if (branch)
@@ -278,7 +278,7 @@ void arch_do_displaced_inst(os_context_t *context,unsigned int orig_inst)
 
     /* Figure out where we will end up after running the displaced 
      * instruction */
 
     /* Figure out where we will end up after running the displaced 
      * instruction */
-    if(op == 0x1a || (op&0xf) == 0x30) /* a branch */
+    if (op == 0x1a || (op&0xf) == 0x30) /* a branch */
        /* The cast to long is just to shut gcc up. */
        next_pc = (unsigned int *)((long)emulate_branch(context,orig_inst));
     else
        /* The cast to long is just to shut gcc up. */
        next_pc = (unsigned int *)((long)emulate_branch(context,orig_inst));
     else
@@ -308,8 +308,8 @@ sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context)
      * different opcode so we can test whether we're dealing with a
      * breakpoint or a "system service" */
 
      * different opcode so we can test whether we're dealing with a
      * breakpoint or a "system service" */
 
-    if((*(unsigned int*)(*os_context_pc_addr(context)-4))== BREAKPOINT_INST) {
-       if(after_breakpoint) {
+    if ((*(unsigned int*)(*os_context_pc_addr(context)-4))==BREAKPOINT_INST) {
+       if (after_breakpoint) {
            /* see comments above arch_do_displaced_inst.  This is where
             * we reinsert the breakpoint that we removed earlier */
 
            /* see comments above arch_do_displaced_inst.  This is where
             * we reinsert the breakpoint that we removed earlier */
 
diff --git a/src/runtime/alpha-arch.h b/src/runtime/alpha-arch.h
new file mode 100644 (file)
index 0000000..16aac2b
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ALPHA_ARCH_H
+#define _ALPHA_ARCH_H
+
+#define ARCH_HAS_FLOAT_REGISTERS
+
+#endif /* _ALPHA_ARCH_H */
index 3cb67b3..3597e04 100644 (file)
@@ -43,29 +43,23 @@ size_t os_vm_page_size;
 #include "gencgc.h"
 #endif
 
 #include "gencgc.h"
 #endif
 
-sigcontext_register_t   *
+os_context_register_t   *
 os_context_register_addr(os_context_t *context, int offset)
 {
     return &context->uc_mcontext.sc_regs[offset];
 }
 
 os_context_register_addr(os_context_t *context, int offset)
 {
     return &context->uc_mcontext.sc_regs[offset];
 }
 
-sigcontext_register_t *
-os_context_fpregister_addr(os_context_t *context, int offset)
+os_context_register_t *
+os_context_float_register_addr(os_context_t *context, int offset)
 {
     return &context->uc_mcontext.sc_fpregs[offset];
 }
 
 {
     return &context->uc_mcontext.sc_fpregs[offset];
 }
 
-sigcontext_register_t *
+os_context_register_t *
 os_context_pc_addr(os_context_t *context)
 {
     return &((context->uc_mcontext).sc_pc);
 }
 os_context_pc_addr(os_context_t *context)
 {
     return &((context->uc_mcontext).sc_pc);
 }
-sigcontext_register_t *
-os_context_sp_addr(os_context_t *context)
-{
-    lose("This was supposed to be an x86-only operation");
-    return 0;
-}
 
 sigset_t *
 os_context_sigmask_addr(os_context_t *context)
 
 sigset_t *
 os_context_sigmask_addr(os_context_t *context)
diff --git a/src/runtime/alpha-linux-os.h b/src/runtime/alpha-linux-os.h
new file mode 100644 (file)
index 0000000..c270f2e
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _ALPHA_LINUX_OS_H
+#define _ALPHA_LINUX_OS_H
+
+typedef struct ucontext os_context_t;
+
+static inline os_context_t *arch_os_get_context(void **void_context) {
+  return (os_context_t *) *void_context;
+}
+
+#endif /* _ALPHA_LINUX_OS_H */
index f2ed91e..63da20b 100644 (file)
@@ -21,6 +21,7 @@ typedef caddr_t os_vm_address_t;
 typedef vm_size_t os_vm_size_t;
 typedef off_t os_vm_offset_t;
 typedef int os_vm_prot_t;
 typedef vm_size_t os_vm_size_t;
 typedef off_t os_vm_offset_t;
 typedef int os_vm_prot_t;
+typedef int os_context_register_t;
 
 #if defined __FreeBSD__
 /* Note: The man page for sigaction(2) in FreeBSD 4.0 says that this
 
 #if defined __FreeBSD__
 /* Note: The man page for sigaction(2) in FreeBSD 4.0 says that this
@@ -39,6 +40,9 @@ typedef struct sigcontext os_context_t;
 #error unsupported BSD variant
 #endif
 
 #error unsupported BSD variant
 #endif
 
+#include "target-arch-os.h"
+#include "target-arch.h"
+
 #define OS_VM_PROT_READ PROT_READ
 #define OS_VM_PROT_WRITE PROT_WRITE
 #define OS_VM_PROT_EXECUTE PROT_EXEC
 #define OS_VM_PROT_READ PROT_READ
 #define OS_VM_PROT_WRITE PROT_WRITE
 #define OS_VM_PROT_EXECUTE PROT_EXEC
index 1be6a63..06b8d26 100644 (file)
 #include "interr.h"
 
 /* So you need to debug? */
 #include "interr.h"
 
 /* So you need to debug? */
-#if 0
 #define PRINTNOISE
 #define DEBUG_SPACE_PREDICATES
 #define PRINTNOISE
 #define DEBUG_SPACE_PREDICATES
+#if 0
+#define DEBUG_SPACE_PREDICATES
 #define DEBUG_SCAVENGE_VERBOSE
 #define DEBUG_COPY_VERBOSE
 #define DEBUG_CODE_GC
 #define DEBUG_SCAVENGE_VERBOSE
 #define DEBUG_COPY_VERBOSE
 #define DEBUG_CODE_GC
@@ -244,7 +245,23 @@ struct timeval start_tv, stop_tv;
            lose("GC lossage.  Current dynamic space is bogus!\n");
        }
        new_space_free_pointer = new_space;
            lose("GC lossage.  Current dynamic space is bogus!\n");
        }
        new_space_free_pointer = new_space;
-
+#if 0
+       /* at one time we had the bright idea of using mprotect() to
+        * hide the semispace that we're not using at the moment, so
+        * we'd see immediately if anyone had a pointer to it.
+        * Unfortunately, if we gc during a call to an assembler
+        * routine with a "raw" return style, at least on PPC we are
+        * expected to return into oldspace because we can't easily
+        * update the link register - it's not tagged, and we can't do
+        * it as an offset of reg_CODE because the calling routine
+        * might be nowhere near our code vector.  We hope that we
+        * don't run very far in oldspace before it catapults us into
+        * newspace by either calling something else or returning
+        */
+
+       /* write-enable */
+       os_protect(new_space,DYNAMIC_SPACE_SIZE,OS_VM_PROT_ALL);
+#endif
 
        /* Initialize the weak pointer list. */
        weak_pointers = (struct weak_pointer *) NULL;
 
        /* Initialize the weak pointer list. */
        weak_pointers = (struct weak_pointer *) NULL;
@@ -365,9 +382,21 @@ struct timeval start_tv, stop_tv;
 #endif        
 
        gc_rate = ((float) size_retained / (float) (1<<20)) / real_time;
 #endif        
 
        gc_rate = ((float) size_retained / (float) (1<<20)) / real_time;
-
+       
        printf("%10.2f M bytes/sec collected.\n", gc_rate);
 #endif
        printf("%10.2f M bytes/sec collected.\n", gc_rate);
 #endif
+       /* os_flush_icache((os_vm_address_t) 0, sizeof(unsigned long)); */
+
+#if 0
+       /* see comment above about mprotecting oldspace */
+
+       /* zero the from space now, to make it easier to find stale
+          pointers to it */
+
+       /* pray that both dynamic spaces are the same size ... */
+       memset(from_space,(DYNAMIC_0_SPACE_END-DYNAMIC_0_SPACE_START-1),0);
+       os_protect(from_space,DYNAMIC_SPACE_SIZE,0); /* write-protect */
+#endif
 }
 
 \f
 }
 
 \f
@@ -413,7 +442,7 @@ scavenge(lispobj *start, u32 nwords)
                         words_scavenged = 1;
                     }
                 }
                         words_scavenged = 1;
                     }
                 }
-               else if(nwords==1) {
+               else if (nwords==1) {
                    /* there are some situations where an
                       other-immediate may end up in a descriptor
                       register.  I'm not sure whether this is
                    /* there are some situations where an
                       other-immediate may end up in a descriptor
                       register.  I'm not sure whether this is
@@ -424,7 +453,7 @@ scavenge(lispobj *start, u32 nwords)
                       other than a pointer, just hush it up */
 
                    words_scavenged=1;
                       other than a pointer, just hush it up */
 
                    words_scavenged=1;
-                   if((scavtab[type]==scav_lose) ||
+                   if ((scavtab[type]==scav_lose) ||
                       (((scavtab[type])(start,object))>1)) {
                        fprintf(stderr,"warning: attempted to scavenge non-descriptor value %x at %p.  If you can\nreproduce this warning, send a test case to sbcl-devel@lists.sourceforge.net\n",
                                object,start);
                       (((scavtab[type])(start,object))>1)) {
                        fprintf(stderr,"warning: attempted to scavenge non-descriptor value %x at %p.  If you can\nreproduce this warning, send a test case to sbcl-devel@lists.sourceforge.net\n",
                                object,start);
@@ -476,10 +505,13 @@ scavenge_interrupt_context(os_context_t *context)
        int lip_register_pair;
 #endif
        unsigned long pc_code_offset;
        int lip_register_pair;
 #endif
        unsigned long pc_code_offset;
-#ifdef SC_NPC
+#ifdef ARCH_HAS_LINK_REGISTER
+       unsigned long lr_code_offset;
+#endif
+#ifdef ARCH_HAS_NPC_REGISTER
        unsigned long npc_code_offset;
 #endif
        unsigned long npc_code_offset;
 #endif
-
+       fprintf(stderr, "Scavenging interrupt context at 0x%x\n",context);
        /* Find the LIP's register pair and calculate its offset */
        /* before we scavenge the context. */
 #ifdef reg_LIP
        /* Find the LIP's register pair and calculate its offset */
        /* before we scavenge the context. */
 #ifdef reg_LIP
@@ -507,13 +539,21 @@ scavenge_interrupt_context(os_context_t *context)
 
        /* Compute the PC's offset from the start of the CODE */
        /* register. */
 
        /* Compute the PC's offset from the start of the CODE */
        /* register. */
-       pc_code_offset = *os_context_pc_addr(context) - 
+       pc_code_offset =
+           *os_context_pc_addr(context) - 
+           *os_context_register_addr(context, reg_CODE);
+#ifdef ARCH_HAS_NPC_REGISTER
+        npc_code_offset =
+           *os_context_npc_addr(context) - 
            *os_context_register_addr(context, reg_CODE);
            *os_context_register_addr(context, reg_CODE);
-#ifdef SC_NPC
-       npc_code_offset = SC_NPC(context) - SC_REG(context, reg_CODE);
-#endif SC_NPC
+#endif 
+#ifdef ARCH_HAS_LINK_REGISTER
+       lr_code_offset =
+           *os_context_lr_addr(context) - 
+           *os_context_register_addr(context, reg_CODE);
+#endif
               
               
-       /* Scanvenge all boxed registers in the context. */
+       /* Scavenge all boxed registers in the context. */
        for (i = 0; i < (sizeof(boxed_registers) / sizeof(int)); i++) {
                int index;
                lispobj foo;
        for (i = 0; i < (sizeof(boxed_registers) / sizeof(int)); i++) {
                int index;
                lispobj foo;
@@ -540,10 +580,20 @@ scavenge_interrupt_context(os_context_t *context)
        if (from_space_p(*os_context_pc_addr(context)))
            *os_context_pc_addr(context) = 
                *os_context_register_addr(context, reg_CODE) + pc_code_offset;
        if (from_space_p(*os_context_pc_addr(context)))
            *os_context_pc_addr(context) = 
                *os_context_register_addr(context, reg_CODE) + pc_code_offset;
-#ifdef SC_NPC
-       if (from_space_p(SC_NPC(context)))
-               SC_NPC(context) = SC_REG(context, reg_CODE) + npc_code_offset;
-#endif SC_NPC
+#ifdef ARCH_HAS_LINK_REGISTER
+       /* Fix the LR ditto; important if we're being called from 
+       * an assembly routine that expects to return using blr, otherwise
+       * harmless */
+       if (from_space_p(*os_context_lr_addr(context)))
+           *os_context_lr_addr(context) = 
+               *os_context_register_addr(context, reg_CODE) + lr_code_offset;
+#endif
+
+#ifdef ARCH_HAS_NPC_REGISTER
+       if (from_space_p(*os_context_npc_addr(context)))
+           *os_context_npc_addr(context) = 
+               *os_context_register_addr(context, reg_CODE) + npc_code_offset;
+#endif
 }
 
 void scavenge_interrupt_contexts(void)
 }
 
 void scavenge_interrupt_contexts(void)
@@ -553,6 +603,7 @@ void scavenge_interrupt_contexts(void)
 
     index = fixnum_value(SymbolValue(FREE_INTERRUPT_CONTEXT_INDEX));
 
 
     index = fixnum_value(SymbolValue(FREE_INTERRUPT_CONTEXT_INDEX));
 
+    fprintf(stderr, "%d interrupt contexts to scan\n",index);
     for (i = 0; i < index; i++) {
        context = lisp_interrupt_contexts[i];
        scavenge_interrupt_context(context); 
     for (i = 0; i < index; i++) {
        context = lisp_interrupt_contexts[i];
        scavenge_interrupt_context(context); 
@@ -850,7 +901,7 @@ trans_return_pc_header(lispobj object)
     printf("trans_return_pc_header object=%x, code=%lx\n",object,code);
 #endif
     ncode = trans_code(code);
     printf("trans_return_pc_header object=%x, code=%lx\n",object,code);
 #endif
     ncode = trans_code(code);
-    if(object==0x304748d7) {
+    if (object==0x304748d7) {
        /* monitor_or_something(); */
     }
     ret= ((lispobj) LOW_WORD(ncode) + offset) | OTHER_POINTER_LOWTAG;
        /* monitor_or_something(); */
     }
     ret= ((lispobj) LOW_WORD(ncode) + offset) | OTHER_POINTER_LOWTAG;
@@ -2204,7 +2255,7 @@ void set_auto_gc_trigger(os_vm_size_t dynamic_usage)
     long length =
        DYNAMIC_SPACE_SIZE + (os_vm_address_t)current_dynamic_space - addr;
 
     long length =
        DYNAMIC_SPACE_SIZE + (os_vm_address_t)current_dynamic_space - addr;
 
-    if(addr < (os_vm_address_t)dynamic_space_free_pointer) {
+    if (addr < (os_vm_address_t)dynamic_space_free_pointer) {
        fprintf(stderr,
           "set_auto_gc_trigger: tried to set gc trigger too low! (%d < %p)\n",
                (unsigned int)dynamic_usage,
        fprintf(stderr,
           "set_auto_gc_trigger: tried to set gc trigger too low! (%d < %p)\n",
                (unsigned int)dynamic_usage,
@@ -2233,7 +2284,7 @@ void set_auto_gc_trigger(os_vm_size_t dynamic_usage)
 
 void clear_auto_gc_trigger(void)
 {
 
 void clear_auto_gc_trigger(void)
 {
-    if(current_auto_gc_trigger!=NULL){
+    if (current_auto_gc_trigger!=NULL){
 #if defined(SUNOS) || defined(SOLARIS)/* don't want to force whole space into swapping mode... */
        os_vm_address_t addr=(os_vm_address_t)current_auto_gc_trigger;
        os_vm_size_t length=
 #if defined(SUNOS) || defined(SOLARIS)/* don't want to force whole space into swapping mode... */
        os_vm_address_t addr=(os_vm_address_t)current_auto_gc_trigger;
        os_vm_size_t length=
index 4c56a0a..159a9ae 100644 (file)
 #include <stdlib.h>
 
 #include <signal.h>
 #include <stdlib.h>
 
 #include <signal.h>
-#ifdef mach /* KLUDGE: #ifdef on lowercase symbols? Ick. -- WHN 19990904 */
-#ifdef mips
-#include <mips/cpu.h>
-#endif
-#endif
 
 #include "runtime.h"
 #include "arch.h"
 
 #include "runtime.h"
 #include "arch.h"
@@ -295,6 +290,7 @@ interrupt_handle_pending(os_context_t *context)
        {
            undo_fake_foreign_function_call(context);
         }
        {
            undo_fake_foreign_function_call(context);
         }
+       fprintf(stderr,"interrupt-handle-pending: back from MAYBE_GC\n");
     }
 
     /* FIXME: This isn't very clear. It would be good to reverse
     }
 
     /* FIXME: This isn't very clear. It would be good to reverse
@@ -321,7 +317,10 @@ interrupt_handle_pending(os_context_t *context)
      * anyway. Why we still need to copy the pending_mask into the
      * context given that we're now done with the context anyway, I
      * couldn't say. */
      * anyway. Why we still need to copy the pending_mask into the
      * context given that we're now done with the context anyway, I
      * couldn't say. */
-    memcpy(os_context_sigmask_addr(context), &pending_mask, sizeof(sigset_t));
+#if 0
+    memcpy(os_context_sigmask_addr(context), &pending_mask, 
+          4 /* sizeof(sigset_t) */ );
+#endif
     sigemptyset(&pending_mask);
     if (pending_signal) {
        int signal = pending_signal;
     sigemptyset(&pending_mask);
     if (pending_signal) {
        int signal = pending_signal;
@@ -369,7 +368,7 @@ interrupt_handle_now(int signal, siginfo_t *info, void *void_context)
     if (ARE_SAME_HANDLER(handler.c, SIG_IGN)) {
        return;
     }
     if (ARE_SAME_HANDLER(handler.c, SIG_IGN)) {
        return;
     }
-
+    
 #ifndef __i386__
     were_in_lisp = !foreign_function_call_active;
     if (were_in_lisp)
 #ifndef __i386__
     were_in_lisp = !foreign_function_call_active;
     if (were_in_lisp)
index c5d5485..69d5a41 100644 (file)
@@ -48,6 +48,10 @@ size_t os_vm_page_size;
 #include "gencgc.h"
 #endif
 \f
 #include "gencgc.h"
 #endif
 \f
+
+#ifdef sparc
+int early_kernel = 0;
+#endif
 void os_init(void)
 {
     /* Early versions of Linux don't support the mmap(..) functionality
 void os_init(void)
 {
     /* Early versions of Linux don't support the mmap(..) functionality
@@ -55,12 +59,24 @@ void os_init(void)
     {
         struct utsname name;
        int major_version;
     {
         struct utsname name;
        int major_version;
+#ifdef sparc
+       int minor_version;
+#endif
        uname(&name);
        major_version = atoi(name.release);
        if (major_version < 2) {
            lose("linux major version=%d (can't run in version < 2.0.0)",
                 major_version);
        }
        uname(&name);
        major_version = atoi(name.release);
        if (major_version < 2) {
            lose("linux major version=%d (can't run in version < 2.0.0)",
                 major_version);
        }
+#ifdef sparc
+       /* KLUDGE: This will break if Linux moves to a uname() version number
+        * that has more than one digit initially -- CSR, 2002-02-12 */
+       minor_version = atoi(name.release+2);
+       if (minor_version < 4) {
+           fprintf(stderr,"linux minor version=%d;\n enabling workarounds for SPARC kernel bugs in signal handling.\n", minor_version);
+           early_kernel = 1;
+       }
+#endif
     }
 
     os_vm_page_size = getpagesize();
     }
 
     os_vm_page_size = getpagesize();
@@ -182,7 +198,7 @@ os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
                MAP_PRIVATE | MAP_FILE | MAP_FIXED,
                fd, (off_t) offset);
 
                MAP_PRIVATE | MAP_FILE | MAP_FIXED,
                fd, (off_t) offset);
 
-    if(addr == MAP_FAILED) {
+    if (addr == MAP_FAILED) {
        perror("mmap");
        lose("unexpected mmap(..) failure");
     }
        perror("mmap");
        lose("unexpected mmap(..) failure");
     }
@@ -234,7 +250,7 @@ is_valid_lisp_addr(os_vm_address_t addr)
 void
 sigsegv_handler(int signal, siginfo_t *info, void* void_context)
 {
 void
 sigsegv_handler(int signal, siginfo_t *info, void* void_context)
 {
-    os_context_t *context = (os_context_t*)void_context;
+    os_context_t *context = arch_os_get_context(&void_context);
     void* fault_addr = (void*)context->uc_mcontext.cr2;
     if (!gencgc_handle_wp_violation(fault_addr)) {
        interrupt_handle_now(signal, info, void_context);
     void* fault_addr = (void*)context->uc_mcontext.cr2;
     if (!gencgc_handle_wp_violation(fault_addr)) {
        interrupt_handle_now(signal, info, void_context);
@@ -246,7 +262,7 @@ sigsegv_handler(int signal, siginfo_t *info, void* void_context)
 static void
 sigsegv_handler(int signal, siginfo_t *info, void* void_context)
 {
 static void
 sigsegv_handler(int signal, siginfo_t *info, void* void_context)
 {
-    os_context_t *context = (os_context_t*)void_context;
+    os_context_t *context = arch_os_get_context(&void_context);
     os_vm_address_t addr;
 
 #ifdef __i386__
     os_vm_address_t addr;
 
 #ifdef __i386__
@@ -256,7 +272,7 @@ sigsegv_handler(int signal, siginfo_t *info, void* void_context)
     
     addr = arch_get_bad_addr(signal,info,context);
 
     
     addr = arch_get_bad_addr(signal,info,context);
 
-    if(addr != NULL && 
+    if (addr != NULL && 
        *os_context_register_addr(context,reg_ALLOC) & (1L<<63)){
        /* This is the end of a pseudo-atomic section during which
         * a signal was received.  We must deal with the pending interrupt
        *os_context_register_addr(context,reg_ALLOC) & (1L<<63)){
        /* This is the end of a pseudo-atomic section during which
         * a signal was received.  We must deal with the pending interrupt
index 1206e32..267929f 100644 (file)
@@ -22,6 +22,8 @@
 #include <sys/syscall.h>
 #include <asm/unistd.h>
 #include <linux/version.h>
 #include <sys/syscall.h>
 #include <asm/unistd.h>
 #include <linux/version.h>
+#include "target-arch-os.h"
+#include "target-arch.h"
 
 #define linuxversion(a, b, c) (((a)<<16)+((b)<<8)+(c))
 
 
 #define linuxversion(a, b, c) (((a)<<16)+((b)<<8)+(c))
 
@@ -30,7 +32,7 @@ typedef size_t os_vm_size_t;
 typedef off_t os_vm_offset_t;
 typedef int os_vm_prot_t;
 
 typedef off_t os_vm_offset_t;
 typedef int os_vm_prot_t;
 
-typedef struct ucontext os_context_t;
+/* typedef struct ucontext os_context_t;*/
 
 #define OS_VM_PROT_READ    PROT_READ
 #define OS_VM_PROT_WRITE   PROT_WRITE
 
 #define OS_VM_PROT_READ    PROT_READ
 #define OS_VM_PROT_WRITE   PROT_WRITE
@@ -39,4 +41,4 @@ typedef struct ucontext os_context_t;
 #define SET_FPU_CONTROL_WORD(cw) asm("fldcw %0" : : "m" (cw))
 
 /* /usr/include/asm/sigcontext.h  */
 #define SET_FPU_CONTROL_WORD(cw) asm("fldcw %0" : : "m" (cw))
 
 /* /usr/include/asm/sigcontext.h  */
-typedef long sigcontext_register_t ;
+typedef long os_context_register_t ;
index 8d7f39e..721294d 100644 (file)
@@ -9,25 +9,7 @@
  * files for more information.
  */
 
  * files for more information.
  */
 
-#if defined(mips) || defined(irix)
-#include "mips-lispregs.h"
-#endif
-
-#ifdef sparc
-#include "sparc-lispregs.h"
-#endif
-
-#ifdef __i386__
-#include "x86-lispregs.h"
-#endif
-
-#ifdef parisc
-#include "hppa-lispregs.h"
-#endif
-
-#ifdef alpha
-#include "alpha-lispregs.h"
-#endif
+#include "target-lispregs.h"
 
 #ifndef LANGUAGE_ASSEMBLY
 extern char *lisp_register_names[];
 
 #ifndef LANGUAGE_ASSEMBLY
 extern char *lisp_register_names[];
index 1194ccc..c7ea586 100644 (file)
@@ -47,7 +47,7 @@ os_zero(os_vm_address_t addr, os_vm_size_t length)
        os_invalidate(block_start, block_size);
        addr = os_validate(block_start, block_size);
 
        os_invalidate(block_start, block_size);
        addr = os_validate(block_start, block_size);
 
-       if(addr == NULL || addr != block_start)
+       if (addr == NULL || addr != block_start)
            lose("os_zero: block moved! 0x%08x ==> 0x%08x",
                 block_start,
                 addr);
            lose("os_zero: block moved! 0x%08x ==> 0x%08x",
                 block_start,
                 addr);
@@ -82,15 +82,15 @@ os_reallocate(os_vm_address_t addr, os_vm_size_t old_len, os_vm_size_t len)
     len=os_round_up_size_to_page(len);
     old_len=os_round_up_size_to_page(old_len);
 
     len=os_round_up_size_to_page(len);
     old_len=os_round_up_size_to_page(old_len);
 
-    if(addr==NULL)
+    if (addr==NULL)
        return os_allocate(len);
     else{
        long len_diff=len-old_len;
 
        return os_allocate(len);
     else{
        long len_diff=len-old_len;
 
-       if(len_diff<0)
+       if (len_diff<0)
            os_invalidate(addr+len,-len_diff);
        else{
            os_invalidate(addr+len,-len_diff);
        else{
-           if(len_diff!=0){
+           if (len_diff!=0) {
              os_vm_address_t new=os_allocate(len);
 
              if(new!=NULL){
              os_vm_address_t new=os_allocate(len);
 
              if(new!=NULL){
index 81fec24..b3c313d 100644 (file)
  *   the type used to represent context in a POSIX sigaction SA_SIGACTION
  *   handler, i.e. the actual type of the thing pointed to by the
  *   void* third argument of a handler */
  *   the type used to represent context in a POSIX sigaction SA_SIGACTION
  *   handler, i.e. the actual type of the thing pointed to by the
  *   void* third argument of a handler */
-#if defined __FreeBSD__
-#include "bsd-os.h"
-#elif defined __OpenBSD__
-#include "bsd-os.h"
-#elif defined __linux__
-#include "linux-os.h"
-#else
-#error unsupported OS
-#endif
+
+/*
+ #if defined __FreeBSD__
+ #include "bsd-os.h"
+ #elif defined __OpenBSD__
+ #include "bsd-os.h"
+ #elif defined __linux__
+ #include "linux-os.h"
+ #else
+ #error unsupported OS
+ #endif
+*/
+
+#include "target-os.h"
+
 
 #define OS_VM_PROT_ALL \
   (OS_VM_PROT_READ | OS_VM_PROT_WRITE | OS_VM_PROT_EXECUTE)
 
 #define OS_VM_PROT_ALL \
   (OS_VM_PROT_READ | OS_VM_PROT_WRITE | OS_VM_PROT_EXECUTE)
@@ -108,19 +114,33 @@ extern boolean is_valid_lisp_addr(os_vm_address_t test);
  * register, of the specified offset, for that context. The offset is
  * defined in the storage class (SC) defined in the Lisp virtual
  * machine (i.e. the file "vm.lisp" for the appropriate architecture). */
  * register, of the specified offset, for that context. The offset is
  * defined in the storage class (SC) defined in the Lisp virtual
  * machine (i.e. the file "vm.lisp" for the appropriate architecture). */
-register_t *os_context_register_addr(os_context_t *context, int offset);
+os_context_register_t *
+os_context_register_addr(os_context_t *context, int offset);
+
+/* FIXME: Pending investigation, this #ifdef stays as alpha. If it
+ * turns out that the alpha truly requires this, it can change to
+ * ARCH_HAS_FLOAT_REGISTERS (currently #defined in alpha-arch.h -- CSR
+ * 2002-02-04 */
 #ifdef alpha
 #ifdef alpha
-register_t *os_context_fpregister_addr(os_context_t *context, int offset);
+os_context_register_t *
+os_context_float_register_addr(os_context_t *context, int offset);
 #endif
 
 /* Given a signal context, return the address for storage of the
  * program counter for that context. */
 #endif
 
 /* Given a signal context, return the address for storage of the
  * program counter for that context. */
-register_t *os_context_pc_addr(os_context_t *context);
+os_context_register_t *os_context_pc_addr(os_context_t *context);
+#ifdef ARCH_HAS_NPC_REGISTER
+os_context_register_t *os_context_npc_addr(os_context_t *context);
+#endif
+#ifdef ARCH_HAS_LINK_REGISTER
+os_context_register_t *os_context_lr_addr(os_context_t *context);
+#endif
 
 /* Given a signal context, return the address for storage of the
  * system stack pointer for that context. */
 
 /* Given a signal context, return the address for storage of the
  * system stack pointer for that context. */
-register_t *os_context_sp_addr(os_context_t *context);
-
+#ifdef ARCH_HAS_STACK_POINTER
+os_context_register_t *os_context_sp_addr(os_context_t *context);
+#endif
 /* Given a signal context, return the address for storage of the
  * signal mask for that context. */
 sigset_t *os_context_sigmask_addr(os_context_t *context);
 /* Given a signal context, return the address for storage of the
  * signal mask for that context. */
 sigset_t *os_context_sigmask_addr(os_context_t *context);
index 8534cbb..2cc6f1b 100644 (file)
@@ -27,7 +27,6 @@
 /* This file can be skipped if we're not supporting LDB. */
 #if defined(LISP_FEATURE_SB_LDB)
 
 /* This file can be skipped if we're not supporting LDB. */
 #if defined(LISP_FEATURE_SB_LDB)
 
-#include "sbcl.h"
 #include "monitor.h"
 #include "vars.h"
 #include "os.h"
 #include "monitor.h"
 #include "vars.h"
 #include "os.h"
@@ -44,11 +43,11 @@ static void print_obj(char *prefix, lispobj obj);
 
 char *lowtag_Names[] = {
     "even fixnum",
 
 char *lowtag_Names[] = {
     "even fixnum",
-    "function pointer",
+    "instance pointer",
     "other immediate [0]",
     "list pointer",
     "odd fixnum",
     "other immediate [0]",
     "list pointer",
     "odd fixnum",
-    "instance pointer",
+    "function pointer",
     "other immediate [1]",
     "other pointer"
 };
     "other immediate [1]",
     "other pointer"
 };
@@ -416,7 +415,8 @@ static char *symbol_slots[] = {"value: ", "unused: ",
 static char *ratio_slots[] = {"numer: ", "denom: ", NULL};
 static char *complex_slots[] = {"real: ", "imag: ", NULL};
 static char *code_slots[] = {"words: ", "entry: ", "debug: ", NULL};
 static char *ratio_slots[] = {"numer: ", "denom: ", NULL};
 static char *complex_slots[] = {"real: ", "imag: ", NULL};
 static char *code_slots[] = {"words: ", "entry: ", "debug: ", NULL};
-static char *fn_slots[] = {"self: ", "next: ", "name: ", "arglist: ", "type: ", NULL};
+static char *fn_slots[] = {
+    "self: ", "next: ", "name: ", "arglist: ", "type: ", NULL};
 static char *closure_slots[] = {"fn: ", NULL};
 static char *funcallable_instance_slots[] = {"fn: ", "lexenv: ", "layout: ", NULL};
 static char *weak_pointer_slots[] = {"value: ", NULL};
 static char *closure_slots[] = {"fn: ", NULL};
 static char *funcallable_instance_slots[] = {"fn: ", "lexenv: ", "layout: ", NULL};
 static char *weak_pointer_slots[] = {"value: ", NULL};
@@ -652,11 +652,11 @@ static void print_otherptr(lispobj obj)
 static void print_obj(char *prefix, lispobj obj)
 {
     static void (*verbose_fns[])(lispobj obj)
 static void print_obj(char *prefix, lispobj obj)
 {
     static void (*verbose_fns[])(lispobj obj)
-       = {print_fixnum, print_otherptr, print_otherimm, print_list,
-          print_fixnum, print_struct, print_otherimm, print_otherptr};
+       = {print_fixnum, print_struct, print_otherimm, print_list,
+          print_fixnum, print_otherptr, print_otherimm, print_otherptr};
     static void (*brief_fns[])(lispobj obj)
     static void (*brief_fns[])(lispobj obj)
-       = {brief_fixnum, brief_otherptr, brief_otherimm, brief_list,
-          brief_fixnum, brief_struct, brief_otherimm, brief_otherptr};
+       = {brief_fixnum, brief_struct, brief_otherimm, brief_list,
+          brief_fixnum, brief_otherptr, brief_otherimm, brief_otherptr};
     int type = lowtag_of(obj);
     struct var *var = lookup_by_obj(obj);
     char buffer[256];
     int type = lowtag_of(obj);
     struct var *var = lookup_by_obj(obj);
     char buffer[256];
index ba5d88e..4d7e1ee 100644 (file)
@@ -97,11 +97,9 @@ static boolean
 dynamic_pointer_p(lispobj ptr)
 {
 #ifndef __i386__
 dynamic_pointer_p(lispobj ptr)
 {
 #ifndef __i386__
-    /* KLUDGE: This has an implicit dependence on the ordering of
-     * address spaces, and is therefore basically wrong. I'd fix it,
-     * but I don't have a non-386 port to test it on. Porters are
-     * encouraged to fix it. -- WHN 2000-10-17 */
-    return (ptr >= (lispobj)DYNAMIC_SPACE_START);
+    return (ptr >= (lispobj)current_dynamic_space
+           &&
+           ptr < (lispobj)dynamic_space_free_pointer);
 #else
     /* Be more conservative, and remember, this is a maybe. */
     return (ptr >= (lispobj)DYNAMIC_SPACE_START
 #else
     /* Be more conservative, and remember, this is a maybe. */
     return (ptr >= (lispobj)DYNAMIC_SPACE_START
@@ -181,7 +179,7 @@ valid_dynamic_space_pointer(lispobj *pointer, lispobj *start_addr)
            return 0;
        }
        /* Is it plausible cons? */
            return 0;
        }
        /* Is it plausible cons? */
-       if((is_lisp_pointer(start_addr[0])
+       if ((is_lisp_pointer(start_addr[0])
            || ((start_addr[0] & 3) == 0) /* fixnum */
            || (widetag_of(start_addr[0]) == BASE_CHAR_WIDETAG)
            || (widetag_of(start_addr[0]) == UNBOUND_MARKER_WIDETAG))
            || ((start_addr[0] & 3) == 0) /* fixnum */
            || (widetag_of(start_addr[0]) == BASE_CHAR_WIDETAG)
            || (widetag_of(start_addr[0]) == UNBOUND_MARKER_WIDETAG))
@@ -221,8 +219,8 @@ valid_dynamic_space_pointer(lispobj *pointer, lispobj *start_addr)
            }
            return 0;
        }
            }
            return 0;
        }
-       /* Is it plausible?  Not a cons. X should check the headers. */
-       if(is_lisp_pointer(start_addr[0]) || ((start_addr[0] & 3) == 0)) {
+       /* Is it plausible? Not a cons. XXX should check the headers. */
+       if (is_lisp_pointer(start_addr[0]) || ((start_addr[0] & 3) == 0)) {
            if (pointer_filter_verbose) {
                fprintf(stderr,"*Wo2: %x %x %x\n", (unsigned int) pointer, 
                        (unsigned int) start_addr, *start_addr);
            if (pointer_filter_verbose) {
                fprintf(stderr,"*Wo2: %x %x %x\n", (unsigned int) pointer, 
                        (unsigned int) start_addr, *start_addr);
@@ -728,7 +726,7 @@ ptrans_code(lispobj thing)
     /* Arrange to scavenge the debug info later. */
     pscav_later(&new->debug_info, 1);
 
     /* Arrange to scavenge the debug info later. */
     pscav_later(&new->debug_info, 1);
 
-    if(new->trace_table_offset & 0x3)
+    if (new->trace_table_offset & 0x3)
 #if 0
       pscav(&new->trace_table_offset, 1, 0);
 #else
 #if 0
       pscav(&new->trace_table_offset, 1, 0);
 #else
diff --git a/src/runtime/sparc-arch.c b/src/runtime/sparc-arch.c
new file mode 100644 (file)
index 0000000..6f6cde2
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+
+ $Header$
+
+ This code was written as part of the CMU Common Lisp project at
+ Carnegie Mellon University, and has been placed in the public domain.
+
+*/
+
+#include <stdio.h>
+
+#include "runtime.h"
+#include "arch.h"
+#include "sbcl.h"
+#include "globals.h"
+#include "validate.h"
+#include "os.h"
+#include "lispregs.h"
+#include "signal.h"
+#include "alloc.h"
+#include "interrupt.h"
+#include "interr.h"
+#include "breakpoint.h"
+#include "monitor.h"
+
+#ifdef linux
+extern int early_kernel;
+#endif
+
+void arch_init(void)
+{
+    return;
+}
+
+os_vm_address_t arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context)
+{
+    unsigned long badinst;
+    unsigned long *pc;
+    int rs1; 
+
+    pc = (unsigned long *)(*os_context_pc_addr(context));
+
+    /* On the sparc, we have to decode the instruction. */
+
+    /* Make sure it's not the pc thats bogus, and that it was lisp code */
+    /* that caused the fault. */
+    if ((unsigned long) pc & 3) {
+      /* Unaligned */
+      return NULL;
+    }
+    if ((pc < READ_ONLY_SPACE_START || 
+        pc >= READ_ONLY_SPACE_START+READ_ONLY_SPACE_SIZE) &&
+       (pc < current_dynamic_space ||
+         pc >= current_dynamic_space + DYNAMIC_SPACE_SIZE)) {
+      return NULL;
+    }
+
+    badinst = *pc;
+
+    if ((badinst >> 30) != 3)
+       /* All load/store instructions have op = 11 (binary) */
+       return 0;
+
+    rs1 = (badinst>>14)&0x1f;
+
+    if (badinst & (1<<13)) {
+       /* r[rs1] + simm(13) */
+       int simm13 = badinst & 0x1fff;
+
+       if (simm13 & (1<<12))
+           simm13 |= -1<<13;
+
+       return (os_vm_address_t)
+         (*os_context_register_addr(context, rs1)+simm13);
+    }
+    else {
+       /* r[rs1] + r[rs2] */
+       int rs2 = badinst & 0x1f;
+
+       return (os_vm_address_t)
+         (*os_context_register_addr(context, rs1) + 
+          *os_context_register_addr(context, rs2));
+    }
+}
+
+void arch_skip_instruction(os_context_t *context)
+{
+  ((char *) *os_context_pc_addr(context)) = ((char *) *os_context_npc_addr(context));
+  context->si_regs.npc += 4;
+}
+
+unsigned char *arch_internal_error_arguments(os_context_t *context)
+{
+  return (unsigned char *)(*os_context_pc_addr(context) + 4);
+}
+
+boolean arch_pseudo_atomic_atomic(os_context_t *context)
+{
+  return ((*os_context_register_addr(context,reg_ALLOC)) & 4);
+}
+
+void arch_set_pseudo_atomic_interrupted(os_context_t *context)
+{
+  *os_context_register_addr(context,reg_ALLOC) |=  1;
+}
+
+unsigned long arch_install_breakpoint(void *pc)
+{
+  unsigned long *ptr = (unsigned long *)pc;
+  unsigned long result = *ptr;
+  *ptr = trap_Breakpoint;
+  
+  os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
+  
+  return result;
+}
+
+void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
+{
+  *(unsigned long *)pc = orig_inst;
+  os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
+}
+
+static unsigned long *skipped_break_addr, displaced_after_inst;
+static sigset_t orig_sigmask;
+
+void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
+{
+  unsigned long *pc = (unsigned long *)(*os_context_pc_addr(context));
+  /* FIXME */
+  unsigned long *npc = &context->si_regs.npc;
+
+  /*  orig_sigmask = context->sigmask;
+      sigemptyset(&context->sigmask); */
+  /* FIXME!!! */
+  /* FILLBLOCKSET(&context->uc_sigmask);*/
+
+  *pc = orig_inst;
+  os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
+  skipped_break_addr = pc;
+  displaced_after_inst = *npc;
+  *npc = trap_AfterBreakpoint;
+  os_flush_icache((os_vm_address_t) npc, sizeof(unsigned long));
+
+  /* How much is this not going to work? */
+  sigreturn(context);
+}
+
+static int pseudo_atomic_trap_p(os_context_t *context)
+{
+  unsigned int* pc;
+  unsigned int badinst;
+  int result;
+  
+  
+  pc = (unsigned int*) *os_context_pc_addr(context);
+  badinst = *pc;
+  result = 0;
+
+  /* Check to see if the current instruction is a trap #x40 */
+  /* FIXME: As written, this will not work when someone comes to port
+     this to Solaris. We have chosen trap 0x40 on SPARC Linux because
+     trap 0x10, used in CMUCL/Solaris, generates a sigtrap rather than
+     a sigill. This number should not be hardcoded, but should come,
+     if possible, from src/compiler/target/parms.lisp via sbcl.h --
+     CSR */
+  if (((badinst >> 30) == 2) && (((badinst >> 19) & 0x3f) == 0x3a)
+      && (((badinst >> 13) & 1) == 1) && ((badinst & 0x7f) == 0x40))
+    {
+      unsigned int previnst;
+      previnst = pc[-1];
+      /*
+       * Check to see if the previous instruction was an andcc alloc-tn,
+       * 3, zero-tn instruction.
+       */
+      if (((previnst >> 30) == 2) && (((previnst >> 19) & 0x3f) == 0x11)
+          && (((previnst >> 14) & 0x1f) == reg_ALLOC)
+          && (((previnst >> 25) & 0x1f) == reg_ZERO)
+          && (((previnst >> 13) & 1) == 1)
+          && ((previnst & 0x1fff) == 3))
+        {
+          result = 1;
+        }
+      else
+        {
+         /* FIXME: in the light of the comment above, this fprintf is
+             bogus. CSR */
+          fprintf(stderr, "Oops!  Got a trap 16 without a preceeding andcc!\n");
+        }
+    }
+  return result;
+}
+
+static void sigill_handler(int signal, siginfo_t *siginfo, void *void_context)
+{
+  os_context_t *context = arch_os_get_context(&void_context);
+
+  sigprocmask(SIG_SETMASK, &context->si_mask, 0);
+
+  if ((siginfo->si_code) == ILL_ILLOPC
+#ifdef linux
+      || (early_kernel && (siginfo->si_code == 2))
+#endif
+      ) {
+    int trap;
+    unsigned int inst;
+    unsigned int* pc = (unsigned int*) siginfo->si_addr;
+
+    inst = *pc;
+    trap = inst & 0x3fffff;
+    
+    switch (trap) {
+    case trap_PendingInterrupt:
+      arch_skip_instruction(context);
+      interrupt_handle_pending(context);
+      break;
+
+    case trap_Halt:
+      fake_foreign_function_call(context);
+      lose("%%primitive halt called; the party is over.\n");
+      
+    case trap_Error:
+    case trap_Cerror:
+      interrupt_internal_error(signal, siginfo, context, trap == trap_Cerror);
+      break;
+
+    case trap_Breakpoint:
+      handle_breakpoint(signal, siginfo, context);
+      break;
+
+    case trap_FunEndBreakpoint:
+      *os_context_pc_addr(context) = (int) handle_fun_end_breakpoint(signal, siginfo, context);
+      context->si_regs.npc = *os_context_pc_addr(context) + 4;
+      break;
+
+    case trap_AfterBreakpoint:
+      *skipped_break_addr = trap_Breakpoint;
+      skipped_break_addr = NULL;
+      *(unsigned long *) os_context_pc_addr(context) = displaced_after_inst;
+      /* context->sigmask = orig_sigmask; */
+      os_flush_icache((os_vm_address_t) os_context_pc_addr(context), sizeof(unsigned long));
+      break;
+      
+    default:
+      interrupt_handle_now(signal, siginfo, context);
+      break;
+    }
+  }
+  else if ((siginfo->si_code) == ILL_ILLTRP
+#ifdef linux
+          || (early_kernel && (siginfo->si_code) == 192)
+#endif
+          ) {
+    if (pseudo_atomic_trap_p(context)) {
+      /* A trap instruction from a pseudo-atomic.  We just need
+        to fixup up alloc-tn to remove the interrupted flag,
+        skip over the trap instruction, and then handle the
+        pending interrupt(s). */
+      *os_context_register_addr(context, reg_ALLOC) &= ~7;
+      arch_skip_instruction(context);
+      interrupt_handle_pending(context);
+    }
+    else {
+      interrupt_internal_error(signal, siginfo, context, 0);
+    }
+  }
+  else {
+    interrupt_handle_now(signal, siginfo, context);
+  }
+}
+
+static void sigemt_handler(int signal, siginfo_t *siginfo, void *void_context)
+{
+  unsigned long badinst;
+  boolean subtract, immed;
+  int rd, rs1, op1, rs2, op2, result;
+  os_context_t *context = arch_os_get_context(&void_context);
+
+  badinst = *(unsigned long *)os_context_pc_addr(context);
+  if ((badinst >> 30) != 2 || ((badinst >> 20) & 0x1f) != 0x11) {
+    /* It wasn't a tagged add.  Pass the signal into lisp. */
+    interrupt_handle_now(signal, siginfo, context);
+    return;
+  }
+
+  fprintf(stderr, "SIGEMT trap handler with tagged op instruction!\n");
+  
+  /* Extract the parts of the inst. */
+  subtract = badinst & (1<<19);
+  rs1 = (badinst>>14) & 0x1f;
+  op1 = *os_context_register_addr(context, rs1);
+  
+  /* If the first arg is $ALLOC then it is really a signal-pending note */
+  /* for the pseudo-atomic noise. */
+  if (rs1 == reg_ALLOC) {
+    /* Perform the op anyway. */
+    op2 = badinst & 0x1fff;
+    if (op2 & (1<<12))
+      op2 |= -1<<13;
+    if (subtract)
+      result = op1 - op2;
+    else
+      result = op1 + op2;
+    *os_context_register_addr(context, reg_ALLOC) = result & ~7;
+    arch_skip_instruction(context);
+    interrupt_handle_pending(context);
+    return;
+  }
+
+  if ((op1 & 3) != 0) {
+    /* The first arg wan't a fixnum. */
+    interrupt_internal_error(signal, siginfo, context, 0);
+    return;
+  }
+
+  if (immed = badinst & (1<<13)) {
+    op2 = badinst & 0x1fff;
+    if (op2 & (1<<12))
+      op2 |= -1<<13;
+  }
+  else {
+    rs2 = badinst & 0x1f;
+    op2 = *os_context_register_addr(context, rs2);
+  }
+
+  if ((op2 & 3) != 0) {
+    /* The second arg wan't a fixnum. */
+    interrupt_internal_error(signal, siginfo, context, 0);
+    return;
+  }
+
+  rd = (badinst>>25) & 0x1f;
+  if (rd != 0) {
+    /* Don't bother computing the result unless we are going to use it. */
+    if (subtract)
+      result = (op1>>2) - (op2>>2);
+    else
+      result = (op1>>2) + (op2>>2);
+    
+    dynamic_space_free_pointer =
+      (lispobj *) *os_context_register_addr(context, reg_ALLOC);
+
+    *os_context_register_addr(context, rd) = alloc_number(result);
+    
+    *os_context_register_addr(context, reg_ALLOC) =
+      (unsigned long) dynamic_space_free_pointer;
+  }
+
+  arch_skip_instruction(context);
+}
+
+void arch_install_interrupt_handlers()
+{
+  undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler);
+  undoably_install_low_level_interrupt_handler(SIGEMT, sigemt_handler);
+}
+
+\f
+extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
+
+lispobj funcall0(lispobj function)
+{
+    lispobj *args = current_control_stack_pointer;
+
+    return call_into_lisp(function, args, 0);
+}
+
+lispobj funcall1(lispobj function, lispobj arg0)
+{
+    lispobj *args = current_control_stack_pointer;
+
+    current_control_stack_pointer += 1;
+    args[0] = arg0;
+
+    return call_into_lisp(function, args, 1);
+}
+
+lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
+{
+    lispobj *args = current_control_stack_pointer;
+
+    current_control_stack_pointer += 2;
+    args[0] = arg0;
+    args[1] = arg1;
+
+    return call_into_lisp(function, args, 2);
+}
+
+lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
+{
+    lispobj *args = current_control_stack_pointer;
+
+    current_control_stack_pointer += 3;
+    args[0] = arg0;
+    args[1] = arg1;
+    args[2] = arg2;
+
+    return call_into_lisp(function, args, 3);
+}
diff --git a/src/runtime/sparc-arch.h b/src/runtime/sparc-arch.h
new file mode 100644 (file)
index 0000000..b75247d
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _SPARC_ARCH_H
+#define _SPARC_ARCH_H
+
+#define ARCH_HAS_NPC_REGISTER
+
+#endif /* _SPARC_ARCH_H */
diff --git a/src/runtime/sparc-assem.S b/src/runtime/sparc-assem.S
new file mode 100644 (file)
index 0000000..a6c0303
--- /dev/null
@@ -0,0 +1,295 @@
+#define _ASM
+
+#define FUNCDEF(x)     .type x,@function
+
+#define LANGUAGE_ASSEMBLY
+#include "lispregs.h"
+#include "globals.h"
+#include "sbcl.h"
+
+
+#define load(sym, reg) \
+        sethi %hi(sym), reg; ld [reg+%lo(sym)], reg
+#define store(reg, sym) \
+        sethi %hi(sym), reg_L0; st reg, [reg_L0+%lo(sym)]
+
+/* FIXME */
+#define FRAMESIZE 0x48
+#define ST_FLUSH_WINDOWS 0x03
+#define PSEUDO_ATOMIC_TRAP_NUMBER 64
+       .seg    "text"
+        .global call_into_lisp
+       FUNCDEF(call_into_lisp)
+call_into_lisp:
+        save    %sp, -FRAMESIZE, %sp
+
+       /* Flush all of C's register windows to the stack. */
+       ta      ST_FLUSH_WINDOWS
+
+        /* Save the return address. */
+        st      %i7, [%fp-4]
+
+        /* Clear the descriptor regs. (See sparc/vm.lisp) */
+        mov     reg_ZERO, reg_A0
+        mov     reg_ZERO, reg_A1
+        mov     reg_ZERO, reg_A2
+        mov     reg_ZERO, reg_A3
+        mov     reg_ZERO, reg_A4
+        mov     reg_ZERO, reg_A5
+        mov     reg_ZERO, reg_OCFP
+        mov     reg_ZERO, reg_LRA
+        mov     reg_ZERO, reg_CODE
+
+        /* Establish NIL */
+        set     NIL, reg_NIL
+
+       /* Set the pseudo-atomic flag. */
+       set     4, reg_ALLOC
+
+       /* Turn off foreign function call. */
+        sethi   %hi(foreign_function_call_active), reg_NL0
+        st      reg_ZERO, [reg_NL0+%lo(foreign_function_call_active)]
+
+        /* Load the rest of lisp state. */
+        load(dynamic_space_free_pointer, reg_NL0)
+       add     reg_NL0, reg_ALLOC, reg_ALLOC
+        load(current_binding_stack_pointer, reg_BSP)
+        load(current_control_stack_pointer, reg_CSP)
+        load(current_control_frame_pointer, reg_OCFP)
+
+        /* No longer atomic, and check for interrupt. */
+       sub     reg_ALLOC, 4, reg_ALLOC
+       andcc   reg_ALLOC, 3, reg_ZERO
+       
+       /* OK, this is ridiculous. We badly urgently need this to be
+       centralized, because that's now _three_ places where this
+       number is used. CSR, 2002-02-09 */
+
+       tne     64
+        /* Pass in the args. */
+        sll     %i2, 2, reg_NARGS
+        mov     %i1, reg_CFP
+       mov     %i0, reg_LEXENV
+        ld      [reg_CFP+0], reg_A0
+        ld      [reg_CFP+4], reg_A1
+        ld      [reg_CFP+8], reg_A2
+        ld      [reg_CFP+12], reg_A3
+        ld      [reg_CFP+16], reg_A4
+        ld      [reg_CFP+20], reg_A5
+
+        /* Calculate LRA */
+        set     lra + OTHER_POINTER_LOWTAG, reg_LRA
+
+        /* Indirect closure */
+        ld      [reg_LEXENV+CLOSURE_FUN_OFFSET], reg_CODE
+
+        jmp     reg_CODE+SIMPLE_FUN_CODE_OFFSET
+        nop
+
+        .align  8
+lra:
+        .word   RETURN_PC_HEADER_WIDETAG
+
+        /* Blow off any extra values. */
+        mov     reg_OCFP, reg_CSP
+        nop
+
+        /* Return the one value. */
+        mov     reg_A0, %i0
+
+        /* Turn on pseudo_atomic */
+       add     reg_ALLOC, 4, reg_ALLOC
+
+        /* Store LISP state */
+       andn    reg_ALLOC, 7, reg_NL1
+        store(reg_NL1,dynamic_space_free_pointer)
+        store(reg_BSP,current_binding_stack_pointer)
+        store(reg_CSP,current_control_stack_pointer)
+        store(reg_CFP,current_control_frame_pointer)
+
+        /* No longer in Lisp. */
+        store(reg_NL1,foreign_function_call_active)
+
+        /* Were we interrupted? */
+       sub     reg_ALLOC, 4, reg_ALLOC
+       andcc   reg_ALLOC, 3, reg_ZERO
+       tne     PSEUDO_ATOMIC_TRAP_NUMBER
+
+        /* Back to C we go. */
+       ld      [%sp+FRAMESIZE-4], %i7
+        ret
+        restore        %sp, FRAMESIZE, %sp
+
+        .global call_into_c
+       FUNCDEF(call_into_c)
+call_into_c:
+        /* Build a lisp stack frame */
+        mov     reg_CFP, reg_OCFP
+        mov     reg_CSP, reg_CFP
+        add     reg_CSP, 32, reg_CSP
+        st      reg_OCFP, [reg_CFP]
+        st      reg_CODE, [reg_CFP+8]
+
+        /* Turn on pseudo-atomic. */
+       add     reg_ALLOC, 4, reg_ALLOC
+
+       /* Convert the return address to an offset and save it on the stack. */
+       sub     reg_LIP, reg_CODE, reg_L0
+       add     reg_L0, OTHER_POINTER_LOWTAG, reg_L0
+       st      reg_L0, [reg_CFP+4]
+
+        /* Store LISP state */
+        store(reg_BSP,current_binding_stack_pointer)
+        store(reg_CSP,current_control_stack_pointer)
+        store(reg_CFP,current_control_frame_pointer)
+       /* Use reg_CFP as a work register, and restore it */
+       andn    reg_ALLOC, 7, reg_CFP
+        store(reg_CFP,dynamic_space_free_pointer)
+               load(current_control_frame_pointer, reg_CFP)
+
+        /* No longer in Lisp. */
+        store(reg_CSP,foreign_function_call_active)
+
+        /* Were we interrupted? */
+       sub     reg_ALLOC, 4, reg_ALLOC
+       andcc   reg_ALLOC, 3, reg_ZERO
+       tne     PSEUDO_ATOMIC_TRAP_NUMBER
+
+        /* Into C we go. */
+        call    reg_CFUNC
+        nop
+
+       /*
+        * Note: C calling conventions (32-bit) say that %o0 and %o1
+        * are used to return function results.  In particular 64-bit
+        * results are in %o0 (hi) and %o1 (low).  
+        */
+       
+        /* Re-establish NIL */
+        set     NIL, reg_NIL
+
+       /* Atomic. */
+       set     4, reg_ALLOC
+
+        /* No longer in foreign function call. */
+        sethi   %hi(foreign_function_call_active), reg_NL2
+        st      reg_ZERO, [reg_NL2+%lo(foreign_function_call_active)]
+
+        /* Load the rest of lisp state. */
+        load(dynamic_space_free_pointer, reg_NL2)
+       add     reg_NL2, reg_ALLOC, reg_ALLOC
+        load(current_binding_stack_pointer, reg_BSP)
+        load(current_control_stack_pointer, reg_CSP)
+        load(current_control_frame_pointer, reg_CFP)
+
+       /* Get the return address back. */
+       ld      [reg_CFP+4], reg_LIP
+       ld      [reg_CFP+8], reg_CODE
+       add     reg_LIP, reg_CODE, reg_LIP
+       sub     reg_LIP, OTHER_POINTER_LOWTAG, reg_LIP
+
+        /* No longer atomic. */
+       sub     reg_ALLOC, 4, reg_ALLOC
+       andcc   reg_ALLOC, 3, reg_ZERO
+       tne     PSEUDO_ATOMIC_TRAP_NUMBER
+
+        /* Reset the lisp stack. */
+        /* Note: OCFP is in one of the locals, it gets preserved across C. */
+        mov     reg_CFP, reg_CSP
+        mov     reg_OCFP, reg_CFP
+
+        /* And back into lisp. */
+        ret
+        nop
+
+        .global undefined_tramp
+       FUNCDEF(undefined_tramp)
+        .align  8
+        .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
+undefined_tramp = . + 1
+       .word   undefined_tramp
+        .word   NIL
+        .word   NIL
+        .word   NIL
+        .word   NIL
+
+       b       1f
+        unimp   trap_Cerror
+       .byte   4
+#ifdef type_LongFloat
+        .byte   24
+#else
+       .byte   23
+#endif
+       .byte   254, sc_DescriptorReg, 3
+       .align  4
+1:
+       ld      [reg_FDEFN+FDEFN_RAW_ADDR_OFFSET], reg_CODE
+       jmp     reg_CODE+SIMPLE_FUN_CODE_OFFSET
+       nop
+
+       .global closure_tramp
+       FUNCDEF(closure_tramp)
+       .align  8
+       .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
+closure_tramp = . + 1
+       .word   closure_tramp
+       .word   NIL
+        .word   NIL
+       .word   NIL
+       .word   NIL
+
+       ld      [reg_FDEFN+FDEFN_FUN_OFFSET], reg_LEXENV
+       ld      [reg_LEXENV+CLOSURE_FUN_OFFSET], reg_CODE
+       jmp     reg_CODE+SIMPLE_FUN_CODE_OFFSET
+       nop
+
+
+/*
+ * Function-end breakpoint magic.
+ */
+
+       .text
+       .align  8
+       .global fun_end_breakpoint_guts
+fun_end_breakpoint_guts:
+       .word   RETURN_PC_HEADER_WIDETAG
+       b       1f
+       nop
+       mov     reg_CSP, reg_OCFP
+       add     4, reg_CSP, reg_CSP
+       mov     4, reg_NARGS
+       mov     reg_NIL, reg_A1
+       mov     reg_NIL, reg_A2
+       mov     reg_NIL, reg_A3
+       mov     reg_NIL, reg_A4
+       mov     reg_NIL, reg_A5
+1:
+
+       .global fun_end_breakpoint_trap
+fun_end_breakpoint_trap:
+       unimp   trap_FunEndBreakpoint
+       b       1b
+       nop
+
+       .global fun_end_breakpoint_end
+fun_end_breakpoint_end:
+
+       .global flush_icache
+       FUNCDEF(flush_icache)
+flush_icache:
+        add %o0,%o1,%o2
+1:      iflush %o0                     ! flush instruction cache
+        add %o0,8,%o0
+        cmp %o0,%o2
+        blt 1b
+        nop
+       retl                            ! return from leaf routine
+        nop
+
+       .global save_context
+       FUNCDEF(save_context)
+save_context:
+       ta      ST_FLUSH_WINDOWS        ! flush register windows
+       retl                            ! return from leaf routine
+       nop 
diff --git a/src/runtime/sparc-linux-os.c b/src/runtime/sparc-linux-os.c
new file mode 100644 (file)
index 0000000..236acae
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * This is the SPARC Linux incarnation of arch-dependent OS-dependent
+ * routines. See also "linux-os.c".
+ */
+
+/*
+ * This software is part of the SBCL system. See the README file for
+ * more information.
+ *
+ * This software is derived from the CMU CL system, which was
+ * written at Carnegie Mellon University and released into the
+ * public domain. The software is in the public domain and is
+ * provided with absolutely no warranty. See the COPYING and CREDITS
+ * files for more information.
+ */
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include "./signal.h"
+#include "os.h"
+#include "arch.h"
+#include "globals.h"
+#include "interrupt.h"
+#include "interr.h"
+#include "lispregs.h"
+#include "sbcl.h"
+#include <sys/socket.h>
+#include <sys/utsname.h>
+
+#include <sys/types.h>
+#include <signal.h>
+/* #include <sys/sysinfo.h> */
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "validate.h"
+size_t os_vm_page_size;
+
+#if defined GENCGC              /* unlikely ... */
+#include "gencgc.h"
+#endif
+
+os_context_register_t   *
+os_context_register_addr(os_context_t *context, int offset)
+{
+  /* printf("Offset: %d,", offset);
+     printf("Context: %p\n", context);
+     printf("PC: %x,", context->si_regs.pc);
+     printf("NPC: %x\n", context->si_regs.npc); */
+  if (offset == 0) {
+    static int zero;
+    zero = 0;
+    /* printf("Returning: %p pointing to %p\n", &zero, zero); */
+    return &zero;
+  } else if (offset < 16) {
+    /* printf("Returning: %p pointing to %p\n", &context->si_regs.u_regs[offset], context->si_regs.u_regs[offset]); */
+    return &context->si_regs.u_regs[offset];
+  } else if (offset < 32) {
+    int *sp = (int*) context->si_regs.u_regs[14]; /* Stack Pointer ?? */
+    /* printf("SP: %p\n", sp);
+       printf("Returning: %p pointing to %p\n", &(sp[offset-16]), sp[offset-16]); */
+    return &(sp[offset-16]);
+  } else
+    return 0;
+}
+
+os_context_register_t *
+os_context_pc_addr(os_context_t *context)
+{
+  return &(context->si_regs.pc);
+}
+
+os_context_register_t *
+os_context_npc_addr(os_context_t *context)
+{
+  return &(context->si_regs.npc);
+}
+
+sigset_t *
+os_context_sigmask_addr(os_context_t *context)
+{
+  return &(context->si_mask);
+}
+
+void os_flush_icache(os_vm_address_t address, os_vm_size_t length)
+{
+  /* FIXME.  There's a bit of stuff in the CMUCL version. It may or
+     may not be needed */
+}
diff --git a/src/runtime/sparc-linux-os.h b/src/runtime/sparc-linux-os.h
new file mode 100644 (file)
index 0000000..a8305f3
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _SPARC_LINUX_OS_H
+#define _SPARC_LINUX_OS_H
+
+typedef struct sigcontext os_context_t;
+
+static inline os_context_t *arch_os_get_context(void **void_context) {
+  asm volatile ("ta 0x03"); /* ta ST_FLUSH_WINDOWS */
+  return (os_context_t *) (void_context + 37);
+}
+
+#endif /* _SPARC_LINUX_OS_H */
diff --git a/src/runtime/sparc-lispregs.h b/src/runtime/sparc-lispregs.h
new file mode 100644 (file)
index 0000000..69c13ce
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * This software is part of the SBCL system. See the README file for
+ * more information.
+ *
+ * This software is derived from the CMU CL system, which was
+ * written at Carnegie Mellon University and released into the
+ * public domain. The software is in the public domain and is
+ * provided with absolutely no warranty. See the COPYING and CREDITS
+ * files for more information.
+ */
+
+
+#define NREGS (32)
+
+#ifdef LANGUAGE_ASSEMBLY
+#define GREG(num) %g##num
+#define OREG(num) %o##num
+#define LREG(num) %l##num
+#define IREG(num) %i##num
+
+#else
+
+#define GREG(num) (num)
+#define OREG(num) ((num)+8)
+#define LREG(num) ((num)+16)
+#define IREG(num) ((num)+24)
+
+#endif
+
+#define reg_ZERO       GREG(0)
+#define reg_ALLOC      GREG(1)
+#define reg_NIL                GREG(2)
+#define reg_CSP                GREG(3)
+#define reg_CFP                GREG(4)
+#define reg_BSP                GREG(5)
+/* %g6 and %g7 are supposed to be reserved for the system */
+
+#define reg_NL0                OREG(0)
+#define reg_NL1                OREG(1)
+#define reg_NL2                OREG(2)
+#define reg_NL3                OREG(3)
+#define reg_NL4                OREG(4)
+#define reg_NL5                OREG(5)
+#define reg_NSP                OREG(6)
+#define reg_NARGS      OREG(7)
+
+#define reg_A0         LREG(0)
+#define reg_A1         LREG(1)
+#define reg_A2         LREG(2)
+#define reg_A3         LREG(3)
+#define reg_A4         LREG(4)
+#define reg_A5         LREG(5)
+#define reg_OCFP       LREG(6)
+#define reg_LRA                LREG(7)
+
+#define reg_FDEFN      IREG(0)
+#define reg_LEXENV     IREG(1)
+#define reg_L0         IREG(2)
+#define reg_NFP                IREG(3)
+#define reg_CFUNC      IREG(4)
+#define reg_CODE       IREG(5)
+#define reg_LIP                IREG(7)
+
+#define REGNAMES \
+       "ZERO",         "ALLOC",        "NULL",         "CSP", \
+       "CFP",          "BSP",          "%g6",          "%g7", \
+        "NL0",         "NL1",          "NL2",          "NL3", \
+        "NL4",         "NL5",          "NSP",          "NARGS", \
+        "A0",          "A1",           "A2",           "A3", \
+        "A4",          "A5",           "OCFP",         "LRA", \
+        "FDEFN",       "LEXENV",       "L0",           "NFP", \
+        "CFUNC",       "CODE",         "???",          "LIP"
+
+#define BOXED_REGISTERS { \
+    reg_A0, reg_A1, reg_A2, reg_A3, reg_A4, reg_A5, reg_FDEFN, reg_LEXENV, \
+    reg_OCFP, reg_LRA, reg_L0, reg_CODE \
+}
diff --git a/src/runtime/x86-arch.h b/src/runtime/x86-arch.h
new file mode 100644 (file)
index 0000000..bbcdcc9
--- /dev/null
@@ -0,0 +1,15 @@
+/* FIXME: Aren't preprocessor symbols with underscore prefixes
+ * reserved for the system libraries? If so, it would be tidy to
+ * rename flags like _X86_ARCH_H so their names are in a part of the
+ * namespace that we control. */
+#ifndef _X86_ARCH_H
+#define _X86_ARCH_H
+
+#define ARCH_HAS_STACK_POINTER
+
+/* FIXME: Do we also want
+ *   #define ARCH_HAS_FLOAT_REGISTERS
+ * here? (The answer wasn't obvious to me when merging the
+ * architecture-abstracting patches for CSR's SPARC port. -- WHN 2002-02-15) */
+
+#endif /* _X86_ARCH_H */
diff --git a/src/runtime/x86-bsd-os.h b/src/runtime/x86-bsd-os.h
new file mode 100644 (file)
index 0000000..d1e39f9
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _X86_LINUX_OS_H
+#define _X86_LINUX_OS_H
+
+static inline os_context_t *arch_os_get_context(void **void_context) {
+  return (os_context_t *) *void_context;
+}
+
+#endif /* _X86_LINUX_OS_H */
index ba3b0e8..ed7a9e0 100644 (file)
@@ -47,7 +47,7 @@ size_t os_vm_page_size;
  * gregs[], but it's conditional on __USE_GNU and not defined, so
  * we need to do this nasty absolute index magic number thing
  * instead. */
  * gregs[], but it's conditional on __USE_GNU and not defined, so
  * we need to do this nasty absolute index magic number thing
  * instead. */
-register_t *
+os_context_register_t *
 os_context_register_addr(os_context_t *context, int offset)
 {
     switch(offset) {
 os_context_register_addr(os_context_t *context, int offset)
 {
     switch(offset) {
@@ -63,12 +63,14 @@ os_context_register_addr(os_context_t *context, int offset)
     }
     return &context->uc_mcontext.gregs[offset];
 }
     }
     return &context->uc_mcontext.gregs[offset];
 }
-register_t *
+
+os_context_register_t *
 os_context_pc_addr(os_context_t *context)
 {
     return &context->uc_mcontext.gregs[14];
 }
 os_context_pc_addr(os_context_t *context)
 {
     return &context->uc_mcontext.gregs[14];
 }
-register_t *
+
+os_context_register_t *
 os_context_sp_addr(os_context_t *context)
 {
     return &context->uc_mcontext.gregs[17];
 os_context_sp_addr(os_context_t *context)
 {
     return &context->uc_mcontext.gregs[17];
diff --git a/src/runtime/x86-linux-os.h b/src/runtime/x86-linux-os.h
new file mode 100644 (file)
index 0000000..02cdfc1
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _X86_LINUX_OS_H
+#define _X86_LINUX_OS_H
+
+typedef struct ucontext os_context_t;
+
+static inline os_context_t *arch_os_get_context(void **void_context) {
+  return (os_context_t *) *void_context;
+}
+
+#endif /* _X86_LINUX_OS_H */
index e756140..6e0b20a 100644 (file)
@@ -18,4 +18,4 @@
 ;;; for internal versions, especially for internal versions off the
 ;;; main CVS branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
 
 ;;; for internal versions, especially for internal versions off the
 ;;; main CVS branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
 
-"0.7.1.19"
+"0.7.1.20"