0.pre7.46:
authorWilliam Harold Newman <william.newman@airmail.net>
Fri, 5 Oct 2001 23:59:26 +0000 (23:59 +0000)
committerWilliam Harold Newman <william.newman@airmail.net>
Fri, 5 Oct 2001 23:59:26 +0000 (23:59 +0000)
various refactorings and tidying..
..redid the hairy remove-ourselves-from-tail-set mess in
MERGE-LETS as a separate function,
DEPART-FROM-TAIL-SET
..split diagnostic/reporting stuff (starting around
(DECLAIM (SPECIAL *CURRENT-PATH*)) out of ir1util.lisp
into ir1report.lisp
..moved UNIX-HOST stuff around in an effort to get rid
of compiler not-defined-(yet) warnings
..split target-pathname.lisp out of pathname.lisp to support
this
..moved target-only HOST stuff from pathname.lisp (which is
built both on host and target) to filesys.lisp (which
is flagged as :NOT-HOST in stems-and-flags.lisp-expr)
..Since there's no longer any numbers.lisp or
host-numbers.lisp to contrast to, target-numbers.lisp
really ought to be called numbers.lisp.
..split ir1-translators.lisp out of ir1tran.lisp (as per FIXME)
..moved IDENTITY, COMPLEMENT, and CONSTANTLY out of list.lisp
into funutils.lisp

14 files changed:
src/code/filesys.lisp
src/code/funutils.lisp [new file with mode: 0644]
src/code/list.lisp
src/code/numbers.lisp [new file with mode: 0644]
src/code/pathname.lisp
src/code/target-numbers.lisp [deleted file]
src/code/target-pathname.lisp
src/compiler/ir1-translators.lisp [new file with mode: 0644]
src/compiler/ir1report.lisp [new file with mode: 0644]
src/compiler/ir1tran.lisp
src/compiler/ir1util.lisp
src/compiler/locall.lisp
stems-and-flags.lisp-expr
version.lisp-expr

index 8464a2c..5e33095 100644 (file)
            (t
             (lose)))))
       (apply #'concatenate 'simple-string (strings)))))
-
-(/show0 "filesys.lisp 471")
-
-(def!struct (unix-host
-            (:make-load-form-fun make-unix-host-load-form)
-            (:include host
-                      (parse #'parse-unix-namestring)
-                      (unparse #'unparse-unix-namestring)
-                      (unparse-host #'unparse-unix-host)
-                      (unparse-directory #'unparse-unix-directory)
-                      (unparse-file #'unparse-unix-file)
-                      (unparse-enough #'unparse-unix-enough)
-                      (customary-case :lower))))
-
-(/show0 "filesys.lisp 486")
-
-(defvar *unix-host* (make-unix-host))
-
-(/show0 "filesys.lisp 488")
-
-(defun make-unix-host-load-form (host)
-  (declare (ignore host))
-  '*unix-host*)
 \f
 ;;;; wildcard matching stuff
 
diff --git a/src/code/funutils.lisp b/src/code/funutils.lisp
new file mode 100644 (file)
index 0000000..ab85f44
--- /dev/null
@@ -0,0 +1,41 @@
+;;;; miscellaneous operations on functions, returning functions, or
+;;;; primarily useful for functional programming
+
+;;;; 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!IMPL")
+
+(defun identity (thing)
+  #!+sb-doc
+  "This function simply returns what was passed to it."
+  thing)
+
+(defun complement (function)
+  #!+sb-doc
+  "Return a new function that returns T whenever FUNCTION returns NIL and
+   NIL whenever FUNCTION returns non-NIL."
+  (lambda (&optional (arg0 nil arg0-p) (arg1 nil arg1-p) (arg2 nil arg2-p)
+                    &rest more-args)
+    (not (cond (more-args (apply function arg0 arg1 arg2 more-args))
+              (arg2-p (funcall function arg0 arg1 arg2))
+              (arg1-p (funcall function arg0 arg1))
+              (arg0-p (funcall function arg0))
+              (t (funcall function))))))
+
+(defun constantly (value)
+  #!+sb-doc
+  "Return a function that always returns VALUE."
+  (lambda ()
+    ;; KLUDGE: This declaration is a hack to make the closure ignore
+    ;; all its arguments without consing a &REST list or anything.
+    ;; Perhaps once DYNAMIC-EXTENT is implemented we won't need to
+    ;; screw around with this kind of thing. -- WHN 2001-04-06
+    (declare (optimize (speed 3) (safety 0)))
+    value))
index 9b07696..2518954 100644 (file)
          assoc-if assoc-if-not rassoc rassoc-if rassoc-if-not subst subst-if
          subst-if-not nsubst nsubst-if nsubst-if-not sublis nsublis))
 
-;;; These functions perform basic list operations:
-(defun car (list) #!+sb-doc "Returns the 1st object in a list." (car list))
+;;; These functions perform basic list operations.
+(defun car (list) #!+sb-doc "Return the 1st object in a list." (car list))
 (defun cdr (list)
-  #!+sb-doc "Returns all but the first object in a list."
+  #!+sb-doc "Return all but the first object in a list."
   (cdr list))
-(defun cadr (list) #!+sb-doc "Returns the 2nd object in a list." (cadr list))
-(defun cdar (list) #!+sb-doc "Returns the cdr of the 1st sublist." (cdar list))
-(defun caar (list) #!+sb-doc "Returns the car of the 1st sublist." (caar list))
+(defun cadr (list) #!+sb-doc "Return the 2nd object in a list." (cadr list))
+(defun cdar (list) #!+sb-doc "Return the cdr of the 1st sublist." (cdar list))
+(defun caar (list) #!+sb-doc "Return the car of the 1st sublist." (caar list))
 (defun cddr (list)
-  #!+sb-doc "Returns all but the 1st two objects of a list."
+  #!+sb-doc "Return all but the 1st two objects of a list."
   (cddr list))
 (defun caddr (list)
-  #!+sb-doc "Returns the 1st object in the cddr of a list."
+  #!+sb-doc "Return the 1st object in the cddr of a list."
   (caddr list))
 (defun caadr (list)
-  #!+sb-doc "Returns the 1st object in the cadr of a list."
+  #!+sb-doc "Return the 1st object in the cadr of a list."
   (caadr list))
 (defun caaar (list)
-  #!+sb-doc "Returns the 1st object in the caar of a list."
+  #!+sb-doc "Return the 1st object in the caar of a list."
   (caaar list))
 (defun cdaar (list)
-  #!+sb-doc "Returns the cdr of the caar of a list."
+  #!+sb-doc "Return the cdr of the caar of a list."
   (cdaar list))
 (defun cddar (list)
-  #!+sb-doc "Returns the cdr of the cdar of a list."
+  #!+sb-doc "Return the cdr of the cdar of a list."
   (cddar list))
 (defun cdddr (list)
-  #!+sb-doc "Returns the cdr of the cddr of a list."
+  #!+sb-doc "Return the cdr of the cddr of a list."
   (cdddr list))
 (defun cadar (list)
-  #!+sb-doc "Returns the car of the cdar of a list."
+  #!+sb-doc "Return the car of the cdar of a list."
   (cadar list))
 (defun cdadr (list)
-  #!+sb-doc "Returns the cdr of the cadr of a list."
+  #!+sb-doc "Return the cdr of the cadr of a list."
   (cdadr list))
 (defun caaaar (list)
-  #!+sb-doc "Returns the car of the caaar of a list."
+  #!+sb-doc "Return the car of the caaar of a list."
   (caaaar list))
 (defun caaadr (list)
-  #!+sb-doc "Returns the car of the caadr of a list."
+  #!+sb-doc "Return the car of the caadr of a list."
   (caaadr list))
 (defun caaddr (list)
-  #!+sb-doc "Returns the car of the caddr of a list."
+  #!+sb-doc "Return the car of the caddr of a list."
   (caaddr list))
 (defun cadddr (list)
-  #!+sb-doc "Returns the car of the cdddr of a list."
+  #!+sb-doc "Return the car of the cdddr of a list."
   (cadddr list))
 (defun cddddr (list)
-  #!+sb-doc "Returns the cdr of the cdddr of a list."
+  #!+sb-doc "Return the cdr of the cdddr of a list."
   (cddddr list))
 (defun cdaaar (list)
-  #!+sb-doc "Returns the cdr of the caaar of a list."
+  #!+sb-doc "Return the cdr of the caaar of a list."
   (cdaaar list))
 (defun cddaar (list)
-  #!+sb-doc "Returns the cdr of the cdaar of a list."
+  #!+sb-doc "Return the cdr of the cdaar of a list."
   (cddaar list))
 (defun cdddar (list)
-  #!+sb-doc "Returns the cdr of the cddar of a list."
+  #!+sb-doc "Return the cdr of the cddar of a list."
   (cdddar list))
 (defun caadar (list)
-  #!+sb-doc "Returns the car of the cadar of a list."
+  #!+sb-doc "Return the car of the cadar of a list."
   (caadar list))
 (defun cadaar (list)
-  #!+sb-doc "Returns the car of the cdaar of a list."
+  #!+sb-doc "Return the car of the cdaar of a list."
   (cadaar list))
 (defun cadadr (list)
-  #!+sb-doc "Returns the car of the cdadr of a list."
+  #!+sb-doc "Return the car of the cdadr of a list."
   (cadadr list))
 (defun caddar (list)
-  #!+sb-doc "Returns the car of the cddar of a list."
+  #!+sb-doc "Return the car of the cddar of a list."
   (caddar list))
 (defun cdaadr (list)
-  #!+sb-doc "Returns the cdr of the caadr of a list."
+  #!+sb-doc "Return the cdr of the caadr of a list."
   (cdaadr list))
 (defun cdadar (list)
-  #!+sb-doc "Returns the cdr of the cadar of a list."
+  #!+sb-doc "Return the cdr of the cadar of a list."
   (cdadar list))
 (defun cdaddr (list)
-  #!+sb-doc "Returns the cdr of the caddr of a list."
+  #!+sb-doc "Return the cdr of the caddr of a list."
   (cdaddr list))
 (defun cddadr (list)
-  #!+sb-doc "Returns the cdr of the cdadr of a list."
+  #!+sb-doc "Return the cdr of the cdadr of a list."
   (cddadr list))
 (defun cons (se1 se2)
-  #!+sb-doc "Returns a list with se1 as the car and se2 as the cdr."
+  #!+sb-doc "Return a list with SE1 as the CAR and SE2 as the CDR."
   (cons se1 se2))
 \f
 (declaim (maybe-inline tree-equal-test tree-equal-test-not))
 ;;;; :KEY arg optimization to save funcall of IDENTITY
 
 ;;; APPLY-KEY saves us a function call sometimes.
-;;;    This is not wrapped in an (EVAL-WHEN (COMPILE EVAL) ..)
-;;;    because this is used in seq.lisp and sort.lisp.
+;;;    This isn't wrapped in an (EVAL-WHEN (COMPILE EVAL) ..)
+;;;    because it's used in seq.lisp and sort.lisp.
 (defmacro apply-key (key element)
   `(if ,key
        (funcall ,key ,element)
        ,element))
-
-(defun identity (thing)
-  #!+sb-doc
-  "This function simply returns what was passed to it."
-  thing)
-
-(defun complement (function)
-  #!+sb-doc
-  "Return a new function that returns T whenever FUNCTION returns NIL and
-   NIL whenever FUNCTION returns non-NIL."
-  (lambda (&optional (arg0 nil arg0-p) (arg1 nil arg1-p) (arg2 nil arg2-p)
-                    &rest more-args)
-    (not (cond (more-args (apply function arg0 arg1 arg2 more-args))
-              (arg2-p (funcall function arg0 arg1 arg2))
-              (arg1-p (funcall function arg0 arg1))
-              (arg0-p (funcall function arg0))
-              (t (funcall function))))))
-
-(defun constantly (value)
-  #!+sb-doc
-  "Return a function that always returns VALUE."
-  (lambda ()
-    ;; KLUDGE: This declaration is a hack to make the closure ignore
-    ;; all its arguments without consing a &REST list or anything.
-    ;; Perhaps once DYNAMIC-EXTENT is implemented we won't need to
-    ;; screw around with this kind of thing. -- WHN 2001-04-06
-    (declare (optimize (speed 3) (safety 0)))
-    value))
 \f
 ;;;; macros for (&KEY (KEY #'IDENTITY) (TEST #'EQL TESTP) (TEST-NOT NIL NOTP))
 
diff --git a/src/code/numbers.lisp b/src/code/numbers.lisp
new file mode 100644 (file)
index 0000000..aa7304a
--- /dev/null
@@ -0,0 +1,1323 @@
+;;;; This file contains the definitions of most number 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!KERNEL")
+\f
+;;;; the NUMBER-DISPATCH macro
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+
+;;; Grovel an individual case to NUMBER-DISPATCH, augmenting RESULT
+;;; with the type dispatches and bodies. Result is a tree built of
+;;; alists representing the dispatching off each arg (in order). The
+;;; leaf is the body to be executed in that case.
+(defun parse-number-dispatch (vars result types var-types body)
+  (cond ((null vars)
+        (unless (null types) (error "More types than vars."))
+        (when (cdr result)
+          (error "Duplicate case: ~S." body))
+        (setf (cdr result)
+              (sublis var-types body :test #'equal)))
+       ((null types)
+        (error "More vars than types."))
+       (t
+        (flet ((frob (var type)
+                 (parse-number-dispatch
+                  (rest vars)
+                  (or (assoc type (cdr result) :test #'equal)
+                      (car (setf (cdr result)
+                                 (acons type nil (cdr result)))))
+                  (rest types)
+                  (acons `(dispatch-type ,var) type var-types)
+                  body)))
+          (let ((type (first types))
+                (var (first vars)))
+            (if (and (consp type) (eq (first type) 'foreach))
+                (dolist (type (rest type))
+                  (frob var type))
+                (frob var type)))))))
+
+;;; our guess for the preferred order in which to do type tests
+;;; (cheaper and/or more probable first.)
+(defparameter *type-test-ordering*
+  '(fixnum single-float double-float integer #!+long-float long-float bignum
+    complex ratio))
+
+;;; Should TYPE1 be tested before TYPE2?
+(defun type-test-order (type1 type2)
+  (let ((o1 (position type1 *type-test-ordering*))
+       (o2 (position type2 *type-test-ordering*)))
+    (cond ((not o1) nil)
+         ((not o2) t)
+         (t
+          (< o1 o2)))))
+
+;;; Return an ETYPECASE form that does the type dispatch, ordering the
+;;; cases for efficiency.
+(defun generate-number-dispatch (vars error-tags cases)
+  (if vars
+      (let ((var (first vars))
+           (cases (sort cases #'type-test-order :key #'car)))
+       `((typecase ,var
+           ,@(mapcar #'(lambda (case)
+                         `(,(first case)
+                           ,@(generate-number-dispatch (rest vars)
+                                                       (rest error-tags)
+                                                       (cdr case))))
+                     cases)
+           (t (go ,(first error-tags))))))
+      cases))
+
+) ; EVAL-WHEN
+
+;;; This is a vaguely case-like macro that does number cross-product
+;;; dispatches. The Vars are the variables we are dispatching off of.
+;;; The Type paired with each Var is used in the error message when no
+;;; case matches. Each case specifies a Type for each var, and is
+;;; executed when that signature holds. A type may be a list
+;;; (FOREACH Each-Type*), causing that case to be repeatedly
+;;; instantiated for every Each-Type. In the body of each case, any
+;;; list of the form (DISPATCH-TYPE Var-Name) is substituted with the
+;;; type of that var in that instance of the case.
+;;;
+;;; As an alternate to a case spec, there may be a form whose CAR is a
+;;; symbol. In this case, we apply the CAR of the form to the CDR and
+;;; treat the result of the call as a list of cases. This process is
+;;; not applied recursively.
+(defmacro number-dispatch (var-specs &body cases)
+  (let ((res (list nil))
+       (vars (mapcar #'car var-specs))
+       (block (gensym)))
+    (dolist (case cases)
+      (if (symbolp (first case))
+         (let ((cases (apply (symbol-function (first case)) (rest case))))
+           (dolist (case cases)
+             (parse-number-dispatch vars res (first case) nil (rest case))))
+         (parse-number-dispatch vars res (first case) nil (rest case))))
+
+    (collect ((errors)
+             (error-tags))
+      (dolist (spec var-specs)
+       (let ((var (first spec))
+             (type (second spec))
+             (tag (gensym)))
+         (error-tags tag)
+         (errors tag)
+         (errors `(return-from
+                   ,block
+                   (error 'simple-type-error :datum ,var
+                          :expected-type ',type
+                          :format-control
+                          "~@<Argument ~A is not a ~S: ~2I~_~S~:>"
+                          :format-arguments
+                          (list ',var ',type ,var))))))
+
+      `(block ,block
+        (tagbody
+          (return-from ,block
+                       ,@(generate-number-dispatch vars (error-tags)
+                                                   (cdr res)))
+          ,@(errors))))))
+\f
+;;;; binary operation dispatching utilities
+
+(eval-when (:compile-toplevel :execute)
+
+;;; Return NUMBER-DISPATCH forms for rational X float.
+(defun float-contagion (op x y &optional (rat-types '(fixnum bignum ratio)))
+  `(((single-float single-float) (,op ,x ,y))
+    (((foreach ,@rat-types)
+      (foreach single-float double-float #!+long-float long-float))
+     (,op (coerce ,x '(dispatch-type ,y)) ,y))
+    (((foreach single-float double-float #!+long-float long-float)
+      (foreach ,@rat-types))
+     (,op ,x (coerce ,y '(dispatch-type ,x))))
+    #!+long-float
+    (((foreach single-float double-float long-float) long-float)
+     (,op (coerce ,x 'long-float) ,y))
+    #!+long-float
+    ((long-float (foreach single-float double-float))
+     (,op ,x (coerce ,y 'long-float)))
+    (((foreach single-float double-float) double-float)
+     (,op (coerce ,x 'double-float) ,y))
+    ((double-float single-float)
+     (,op ,x (coerce ,y 'double-float)))))
+
+;;; Return NUMBER-DISPATCH forms for bignum X fixnum.
+(defun bignum-cross-fixnum (fix-op big-op)
+  `(((fixnum fixnum) (,fix-op x y))
+    ((fixnum bignum)
+     (,big-op (make-small-bignum x) y))
+    ((bignum fixnum)
+     (,big-op x (make-small-bignum y)))
+    ((bignum bignum)
+     (,big-op x y))))
+
+) ; EVAL-WHEN
+\f
+;;;; canonicalization utilities
+
+;;; If IMAGPART is 0, return REALPART, otherwise make a complex. This is
+;;; used when we know that REALPART and IMAGPART are the same type, but
+;;; rational canonicalization might still need to be done.
+#!-sb-fluid (declaim (inline canonical-complex))
+(defun canonical-complex (realpart imagpart)
+  (if (eql imagpart 0)
+      realpart
+      (cond #!+long-float
+           ((and (typep realpart 'long-float)
+                 (typep imagpart 'long-float))
+            (truly-the (complex long-float) (complex realpart imagpart)))
+           ((and (typep realpart 'double-float)
+                 (typep imagpart 'double-float))
+            (truly-the (complex double-float) (complex realpart imagpart)))
+           ((and (typep realpart 'single-float)
+                 (typep imagpart 'single-float))
+            (truly-the (complex single-float) (complex realpart imagpart)))
+           (t
+            (%make-complex realpart imagpart)))))
+
+;;; Given a numerator and denominator with the GCD already divided
+;;; out, make a canonical rational. We make the denominator positive,
+;;; and check whether it is 1.
+#!-sb-fluid (declaim (inline build-ratio))
+(defun build-ratio (num den)
+  (multiple-value-bind (num den)
+      (if (minusp den)
+         (values (- num) (- den))
+         (values num den))
+    (if (eql den 1)
+       num
+       (%make-ratio num den))))
+
+;;; Truncate X and Y, but bum the case where Y is 1.
+#!-sb-fluid (declaim (inline maybe-truncate))
+(defun maybe-truncate (x y)
+  (if (eql y 1)
+      x
+      (truncate x y)))
+\f
+;;;; COMPLEXes
+
+(defun upgraded-complex-part-type (spec)
+  #!+sb-doc
+  "Returns the element type of the most specialized COMPLEX number type that
+   can hold parts of type SPEC."
+  (cond ((unknown-type-p (specifier-type spec))
+        (error "undefined type: ~S" spec))
+       ((subtypep spec 'single-float)
+        'single-float)
+       ((subtypep spec 'double-float)
+        'double-float)
+       #!+long-float
+       ((subtypep spec 'long-float)
+        'long-float)
+       ((subtypep spec 'rational)
+        'rational)
+       (t
+        'real)))
+
+(defun complex (realpart &optional (imagpart 0))
+  #!+sb-doc
+  "Builds a complex number from the specified components."
+  (flet ((%%make-complex (realpart imagpart)
+          (cond #!+long-float
+                ((and (typep realpart 'long-float)
+                      (typep imagpart 'long-float))
+                 (truly-the (complex long-float)
+                            (complex realpart imagpart)))
+                ((and (typep realpart 'double-float)
+                      (typep imagpart 'double-float))
+                 (truly-the (complex double-float)
+                            (complex realpart imagpart)))
+                ((and (typep realpart 'single-float)
+                      (typep imagpart 'single-float))
+                 (truly-the (complex single-float)
+                            (complex realpart imagpart)))
+                (t
+                 (%make-complex realpart imagpart)))))
+  (number-dispatch ((realpart real) (imagpart real))
+    ((rational rational)
+     (canonical-complex realpart imagpart))
+    (float-contagion %%make-complex realpart imagpart (rational)))))
+
+(defun realpart (number)
+  #!+sb-doc
+  "Extracts the real part of a number."
+  (typecase number
+    #!+long-float
+    ((complex long-float)
+     (truly-the long-float (realpart number)))
+    ((complex double-float)
+     (truly-the double-float (realpart number)))
+    ((complex single-float)
+     (truly-the single-float (realpart number)))
+    ((complex rational)
+     (sb!kernel:%realpart number))
+    (t
+     number)))
+
+(defun imagpart (number)
+  #!+sb-doc
+  "Extracts the imaginary part of a number."
+  (typecase number
+    #!+long-float
+    ((complex long-float)
+     (truly-the long-float (imagpart number)))
+    ((complex double-float)
+     (truly-the double-float (imagpart number)))
+    ((complex single-float)
+     (truly-the single-float (imagpart number)))
+    ((complex rational)
+     (sb!kernel:%imagpart number))
+    (float
+     (float 0 number))
+    (t
+     0)))
+
+(defun conjugate (number)
+  #!+sb-doc
+  "Returns the complex conjugate of NUMBER. For non-complex numbers, this is
+  an identity."
+  (if (complexp number)
+      (complex (realpart number) (- (imagpart number)))
+      number))
+
+(defun signum (number)
+  #!+sb-doc
+  "If NUMBER is zero, return NUMBER, else return (/ NUMBER (ABS NUMBER))."
+  (if (zerop number)
+      number
+      (if (rationalp number)
+         (if (plusp number) 1 -1)
+         (/ number (abs number)))))
+\f
+;;;; ratios
+
+(defun numerator (number)
+  #!+sb-doc
+  "Return the numerator of NUMBER, which must be rational."
+  (numerator number))
+
+(defun denominator (number)
+  #!+sb-doc
+  "Return the denominator of NUMBER, which must be rational."
+  (denominator number))
+\f
+;;;; arithmetic operations
+
+(macrolet ((define-arith (op init doc)
+            #!-sb-doc (declare (ignore doc))
+            `(defun ,op (&rest args)
+               #!+sb-doc ,doc
+               (if (null args) ,init
+                 (do ((args (cdr args) (cdr args))
+                      (res (car args) (,op res (car args))))
+                     ((null args) res))))))
+  (define-arith + 0
+    "Returns the sum of its arguments. With no args, returns 0.")
+  (define-arith * 1
+    "Returns the product of its arguments. With no args, returns 1."))
+
+(defun - (number &rest more-numbers)
+  #!+sb-doc
+  "Subtracts the second and all subsequent arguments from the first.
+  With one arg, negates it."
+  (if more-numbers
+      (do ((nlist more-numbers (cdr nlist))
+          (result number))
+         ((atom nlist) result)
+        (declare (list nlist))
+        (setq result (- result (car nlist))))
+      (- number)))
+
+(defun / (number &rest more-numbers)
+  #!+sb-doc
+  "Divide the first argument by each of the following arguments, in turn.
+  With one argument, return reciprocal."
+  (if more-numbers
+      (do ((nlist more-numbers (cdr nlist))
+          (result number))
+         ((atom nlist) result)
+        (declare (list nlist))
+        (setq result (/ result (car nlist))))
+      (/ number)))
+
+(defun 1+ (number)
+  #!+sb-doc
+  "Returns NUMBER + 1."
+  (1+ number))
+
+(defun 1- (number)
+  #!+sb-doc
+  "Returns NUMBER - 1."
+  (1- number))
+
+(eval-when (:compile-toplevel)
+
+(sb!xc:defmacro two-arg-+/- (name op big-op)
+  `(defun ,name (x y)
+     (number-dispatch ((x number) (y number))
+       (bignum-cross-fixnum ,op ,big-op)
+       (float-contagion ,op x y)
+
+       ((complex complex)
+       (canonical-complex (,op (realpart x) (realpart y))
+                          (,op (imagpart x) (imagpart y))))
+       (((foreach bignum fixnum ratio single-float double-float
+                 #!+long-float long-float) complex)
+       (complex (,op x (realpart y)) (,op (imagpart y))))
+       ((complex (or rational float))
+       (complex (,op (realpart x) y) (imagpart x)))
+
+       (((foreach fixnum bignum) ratio)
+       (let* ((dy (denominator y))
+              (n (,op (* x dy) (numerator y))))
+         (%make-ratio n dy)))
+       ((ratio integer)
+       (let* ((dx (denominator x))
+              (n (,op (numerator x) (* y dx))))
+         (%make-ratio n dx)))
+       ((ratio ratio)
+       (let* ((nx (numerator x))
+              (dx (denominator x))
+              (ny (numerator y))
+              (dy (denominator y))
+              (g1 (gcd dx dy)))
+         (if (eql g1 1)
+             (%make-ratio (,op (* nx dy) (* dx ny)) (* dx dy))
+             (let* ((t1 (,op (* nx (truncate dy g1)) (* (truncate dx g1) ny)))
+                    (g2 (gcd t1 g1))
+                    (t2 (truncate dx g1)))
+               (cond ((eql t1 0) 0)
+                     ((eql g2 1)
+                      (%make-ratio t1 (* t2 dy)))
+                     (T (let* ((nn (truncate t1 g2))
+                               (t3 (truncate dy g2))
+                               (nd (if (eql t2 1) t3 (* t2 t3))))
+                          (if (eql nd 1) nn (%make-ratio nn nd))))))))))))
+
+); Eval-When (Compile)
+
+(two-arg-+/- two-arg-+ + add-bignums)
+(two-arg-+/- two-arg-- - subtract-bignum)
+
+(defun two-arg-* (x y)
+  (flet ((integer*ratio (x y)
+          (if (eql x 0) 0
+              (let* ((ny (numerator y))
+                     (dy (denominator y))
+                     (gcd (gcd x dy)))
+                (if (eql gcd 1)
+                    (%make-ratio (* x ny) dy)
+                    (let ((nn (* (truncate x gcd) ny))
+                          (nd (truncate dy gcd)))
+                      (if (eql nd 1)
+                          nn
+                          (%make-ratio nn nd)))))))
+        (complex*real (x y)
+          (canonical-complex (* (realpart x) y) (* (imagpart x) y))))
+    (number-dispatch ((x number) (y number))
+      (float-contagion * x y)
+
+      ((fixnum fixnum) (multiply-fixnums x y))
+      ((bignum fixnum) (multiply-bignum-and-fixnum x y))
+      ((fixnum bignum) (multiply-bignum-and-fixnum y x))
+      ((bignum bignum) (multiply-bignums x y))
+
+      ((complex complex)
+       (let* ((rx (realpart x))
+             (ix (imagpart x))
+             (ry (realpart y))
+             (iy (imagpart y)))
+        (canonical-complex (- (* rx ry) (* ix iy)) (+ (* rx iy) (* ix ry)))))
+      (((foreach bignum fixnum ratio single-float double-float
+                #!+long-float long-float)
+       complex)
+       (complex*real y x))
+      ((complex (or rational float))
+       (complex*real x y))
+
+      (((foreach bignum fixnum) ratio) (integer*ratio x y))
+      ((ratio integer) (integer*ratio y x))
+      ((ratio ratio)
+       (let* ((nx (numerator x))
+             (dx (denominator x))
+             (ny (numerator y))
+             (dy (denominator y))
+             (g1 (gcd nx dy))
+             (g2 (gcd dx ny)))
+        (build-ratio (* (maybe-truncate nx g1)
+                        (maybe-truncate ny g2))
+                     (* (maybe-truncate dx g2)
+                        (maybe-truncate dy g1))))))))
+
+;;; Divide two integers, producing a canonical rational. If a fixnum,
+;;; we see whether they divide evenly before trying the GCD. In the
+;;; bignum case, we don't bother, since bignum division is expensive,
+;;; and the test is not very likely to succeed.
+(defun integer-/-integer (x y)
+  (if (and (typep x 'fixnum) (typep y 'fixnum))
+      (multiple-value-bind (quo rem) (truncate x y)
+       (if (zerop rem)
+           quo
+           (let ((gcd (gcd x y)))
+             (declare (fixnum gcd))
+             (if (eql gcd 1)
+                 (build-ratio x y)
+                 (build-ratio (truncate x gcd) (truncate y gcd))))))
+      (let ((gcd (gcd x y)))
+       (if (eql gcd 1)
+           (build-ratio x y)
+           (build-ratio (truncate x gcd) (truncate y gcd))))))
+
+(defun two-arg-/ (x y)
+  (number-dispatch ((x number) (y number))
+    (float-contagion / x y (ratio integer))
+
+    ((complex complex)
+     (let* ((rx (realpart x))
+           (ix (imagpart x))
+           (ry (realpart y))
+           (iy (imagpart y)))
+       (if (> (abs ry) (abs iy))
+          (let* ((r (/ iy ry))
+                 (dn (* ry (+ 1 (* r r)))))
+            (canonical-complex (/ (+ rx (* ix r)) dn)
+                               (/ (- ix (* rx r)) dn)))
+          (let* ((r (/ ry iy))
+                 (dn (* iy (+ 1 (* r r)))))
+            (canonical-complex (/ (+ (* rx r) ix) dn)
+                               (/ (- (* ix r) rx) dn))))))
+    (((foreach integer ratio single-float double-float) complex)
+     (let* ((ry (realpart y))
+           (iy (imagpart y)))
+       (if (> (abs ry) (abs iy))
+          (let* ((r (/ iy ry))
+                 (dn (* ry (+ 1 (* r r)))))
+            (canonical-complex (/ x dn)
+                               (/ (- (* x r)) dn)))
+          (let* ((r (/ ry iy))
+                 (dn (* iy (+ 1 (* r r)))))
+            (canonical-complex (/ (* x r) dn)
+                               (/ (- x) dn))))))
+    ((complex (or rational float))
+     (canonical-complex (/ (realpart x) y)
+                       (/ (imagpart x) y)))
+
+    ((ratio ratio)
+     (let* ((nx (numerator x))
+           (dx (denominator x))
+           (ny (numerator y))
+           (dy (denominator y))
+           (g1 (gcd nx ny))
+           (g2 (gcd dx dy)))
+       (build-ratio (* (maybe-truncate nx g1) (maybe-truncate dy g2))
+                   (* (maybe-truncate dx g2) (maybe-truncate ny g1)))))
+
+    ((integer integer)
+     (integer-/-integer x y))
+
+    ((integer ratio)
+     (if (zerop x)
+        0
+        (let* ((ny (numerator y))
+               (dy (denominator y))
+               (gcd (gcd x ny)))
+          (build-ratio (* (maybe-truncate x gcd) dy)
+                       (maybe-truncate ny gcd)))))
+
+    ((ratio integer)
+     (let* ((nx (numerator x))
+           (gcd (gcd nx y)))
+       (build-ratio (maybe-truncate nx gcd)
+                   (* (maybe-truncate y gcd) (denominator x)))))))
+
+(defun %negate (n)
+  (number-dispatch ((n number))
+    (((foreach fixnum single-float double-float #!+long-float long-float))
+     (%negate n))
+    ((bignum)
+     (negate-bignum n))
+    ((ratio)
+     (%make-ratio (- (numerator n)) (denominator n)))
+    ((complex)
+     (complex (- (realpart n)) (- (imagpart n))))))
+\f
+;;;; TRUNCATE and friends
+
+(defun truncate (number &optional (divisor 1))
+  #!+sb-doc
+  "Returns number (or number/divisor) as an integer, rounded toward 0.
+  The second returned value is the remainder."
+  (macrolet ((truncate-float (rtype)
+              `(let* ((float-div (coerce divisor ',rtype))
+                      (res (%unary-truncate (/ number float-div))))
+                 (values res
+                         (- number
+                            (* (coerce res ',rtype) float-div))))))
+    (number-dispatch ((number real) (divisor real))
+      ((fixnum fixnum) (truncate number divisor))
+      (((foreach fixnum bignum) ratio)
+       (let ((q (truncate (* number (denominator divisor))
+                         (numerator divisor))))
+        (values q (- number (* q divisor)))))
+      ((fixnum bignum)
+       (values 0 number))
+      ((ratio (or float rational))
+       (let ((q (truncate (numerator number)
+                         (* (denominator number) divisor))))
+        (values q (- number (* q divisor)))))
+      ((bignum fixnum)
+       (bignum-truncate number (make-small-bignum divisor)))
+      ((bignum bignum)
+       (bignum-truncate number divisor))
+
+      (((foreach single-float double-float #!+long-float long-float)
+       (or rational single-float))
+       (if (eql divisor 1)
+          (let ((res (%unary-truncate number)))
+            (values res (- number (coerce res '(dispatch-type number)))))
+          (truncate-float (dispatch-type number))))
+      #!+long-float
+      ((long-float (or single-float double-float long-float))
+       (truncate-float long-float))
+      #!+long-float
+      (((foreach double-float single-float) long-float)
+       (truncate-float long-float))
+      ((double-float (or single-float double-float))
+       (truncate-float double-float))
+      ((single-float double-float)
+       (truncate-float double-float))
+      (((foreach fixnum bignum ratio)
+       (foreach single-float double-float #!+long-float long-float))
+       (truncate-float (dispatch-type divisor))))))
+
+;;; Declare these guys inline to let them get optimized a little.
+;;; ROUND and FROUND are not declared inline since they seem too
+;;; obscure and too big to inline-expand by default. Also, this gives
+;;; the compiler a chance to pick off the unary float case. Similarly,
+;;; CEILING and FLOOR are only maybe-inline for now, so that the
+;;; power-of-2 CEILING and FLOOR transforms get a chance.
+#!-sb-fluid (declaim (inline rem mod fceiling ffloor ftruncate))
+(declaim (maybe-inline ceiling floor))
+
+(defun floor (number &optional (divisor 1))
+  #!+sb-doc
+  "Returns the greatest integer not greater than number, or number/divisor.
+  The second returned value is (mod number divisor)."
+  ;; If the numbers do not divide exactly and the result of
+  ;; (/ NUMBER DIVISOR) would be negative then decrement the quotient
+  ;; and augment the remainder by the divisor.
+  (multiple-value-bind (tru rem) (truncate number divisor)
+    (if (and (not (zerop rem))
+            (if (minusp divisor)
+                (plusp number)
+                (minusp number)))
+       (values (1- tru) (+ rem divisor))
+       (values tru rem))))
+
+(defun ceiling (number &optional (divisor 1))
+  #!+sb-doc
+  "Returns the smallest integer not less than number, or number/divisor.
+  The second returned value is the remainder."
+  ;; If the numbers do not divide exactly and the result of
+  ;; (/ NUMBER DIVISOR) would be positive then increment the quotient
+  ;; and decrement the remainder by the divisor.
+  (multiple-value-bind (tru rem) (truncate number divisor)
+    (if (and (not (zerop rem))
+            (if (minusp divisor)
+                (minusp number)
+                (plusp number)))
+       (values (+ tru 1) (- rem divisor))
+       (values tru rem))))
+
+(defun round (number &optional (divisor 1))
+  #!+sb-doc
+  "Rounds number (or number/divisor) to nearest integer.
+  The second returned value is the remainder."
+  (if (eql divisor 1)
+      (round number)
+      (multiple-value-bind (tru rem) (truncate number divisor)
+       (let ((thresh (/ (abs divisor) 2)))
+         (cond ((or (> rem thresh)
+                    (and (= rem thresh) (oddp tru)))
+                (if (minusp divisor)
+                    (values (- tru 1) (+ rem divisor))
+                    (values (+ tru 1) (- rem divisor))))
+               ((let ((-thresh (- thresh)))
+                  (or (< rem -thresh)
+                      (and (= rem -thresh) (oddp tru))))
+                (if (minusp divisor)
+                    (values (+ tru 1) (- rem divisor))
+                    (values (- tru 1) (+ rem divisor))))
+               (t (values tru rem)))))))
+
+(defun rem (number divisor)
+  #!+sb-doc
+  "Returns second result of TRUNCATE."
+  (multiple-value-bind (tru rem) (truncate number divisor)
+    (declare (ignore tru))
+    rem))
+
+(defun mod (number divisor)
+  #!+sb-doc
+  "Returns second result of FLOOR."
+  (let ((rem (rem number divisor)))
+    (if (and (not (zerop rem))
+            (if (minusp divisor)
+                (plusp number)
+                (minusp number)))
+       (+ rem divisor)
+       rem)))
+
+(macrolet ((def-frob (name op doc)
+            `(defun ,name (number &optional (divisor 1))
+               ,doc
+               (multiple-value-bind (res rem) (,op number divisor)
+                 (values (float res (if (floatp rem) rem 1.0)) rem)))))
+  (def-frob ffloor floor
+    "Same as FLOOR, but returns first value as a float.")
+  (def-frob fceiling ceiling
+    "Same as CEILING, but returns first value as a float." )
+  (def-frob ftruncate truncate
+    "Same as TRUNCATE, but returns first value as a float.")
+  (def-frob fround round
+    "Same as ROUND, but returns first value as a float."))
+\f
+;;;; comparisons
+
+(defun = (number &rest more-numbers)
+  #!+sb-doc
+  "Returns T if all of its arguments are numerically equal, NIL otherwise."
+  (do ((nlist more-numbers (cdr nlist)))
+      ((atom nlist) T)
+     (declare (list nlist))
+     (if (not (= (car nlist) number)) (return nil))))
+
+(defun /= (number &rest more-numbers)
+  #!+sb-doc
+  "Returns T if no two of its arguments are numerically equal, NIL otherwise."
+  (do* ((head number (car nlist))
+       (nlist more-numbers (cdr nlist)))
+       ((atom nlist) t)
+     (declare (list nlist))
+     (unless (do* ((nl nlist (cdr nl)))
+                 ((atom nl) T)
+              (declare (list nl))
+              (if (= head (car nl)) (return nil)))
+       (return nil))))
+
+(defun < (number &rest more-numbers)
+  #!+sb-doc
+  "Returns T if its arguments are in strictly increasing order, NIL otherwise."
+  (do* ((n number (car nlist))
+       (nlist more-numbers (cdr nlist)))
+       ((atom nlist) t)
+     (declare (list nlist))
+     (if (not (< n (car nlist))) (return nil))))
+
+(defun > (number &rest more-numbers)
+  #!+sb-doc
+  "Returns T if its arguments are in strictly decreasing order, NIL otherwise."
+  (do* ((n number (car nlist))
+       (nlist more-numbers (cdr nlist)))
+       ((atom nlist) t)
+     (declare (list nlist))
+     (if (not (> n (car nlist))) (return nil))))
+
+(defun <= (number &rest more-numbers)
+  #!+sb-doc
+  "Returns T if arguments are in strictly non-decreasing order, NIL otherwise."
+  (do* ((n number (car nlist))
+       (nlist more-numbers (cdr nlist)))
+       ((atom nlist) t)
+     (declare (list nlist))
+     (if (not (<= n (car nlist))) (return nil))))
+
+(defun >= (number &rest more-numbers)
+  #!+sb-doc
+  "Returns T if arguments are in strictly non-increasing order, NIL otherwise."
+  (do* ((n number (car nlist))
+       (nlist more-numbers (cdr nlist)))
+       ((atom nlist) t)
+     (declare (list nlist))
+     (if (not (>= n (car nlist))) (return nil))))
+
+(defun max (number &rest more-numbers)
+  #!+sb-doc
+  "Returns the greatest of its arguments."
+  (do ((nlist more-numbers (cdr nlist))
+       (result number))
+      ((null nlist) (return result))
+     (declare (list nlist))
+     (if (> (car nlist) result) (setq result (car nlist)))))
+
+(defun min (number &rest more-numbers)
+  #!+sb-doc
+  "Returns the least of its arguments."
+  (do ((nlist more-numbers (cdr nlist))
+       (result number))
+      ((null nlist) (return result))
+     (declare (list nlist))
+     (if (< (car nlist) result) (setq result (car nlist)))))
+
+(eval-when (:compile-toplevel :execute)
+
+;;; The INFINITE-X-FINITE-Y and INFINITE-Y-FINITE-X args tell us how
+;;; to handle the case when X or Y is a floating-point infinity and
+;;; the other arg is a rational. (Section 12.1.4.1 of the ANSI spec
+;;; says that comparisons are done by converting the float to a
+;;; rational when comparing with a rational, but infinities can't be
+;;; converted to a rational, so we show some initiative and do it this
+;;; way instead.)
+(defun basic-compare (op &key infinite-x-finite-y infinite-y-finite-x)
+  `(((fixnum fixnum) (,op x y))
+
+    ((single-float single-float) (,op x y))
+    #!+long-float
+    (((foreach single-float double-float long-float) long-float)
+     (,op (coerce x 'long-float) y))
+    #!+long-float
+    ((long-float (foreach single-float double-float))
+     (,op x (coerce y 'long-float)))
+    (((foreach single-float double-float) double-float)
+     (,op (coerce x 'double-float) y))
+    ((double-float single-float)
+     (,op x (coerce y 'double-float)))
+    (((foreach single-float double-float #!+long-float long-float) rational)
+     (if (eql y 0)
+        (,op x (coerce 0 '(dispatch-type x)))
+        (if (float-infinity-p x)
+            ,infinite-x-finite-y
+            (,op (rational x) y))))
+    (((foreach bignum fixnum ratio) float)
+     (if (float-infinity-p y)
+        ,infinite-y-finite-x
+        (,op x (rational y))))))
+) ; EVAL-WHEN
+
+(macrolet ((def-two-arg-</> (name op ratio-arg1 ratio-arg2 &rest cases)
+             `(defun ,name (x y)
+               (number-dispatch ((x real) (y real))
+                                (basic-compare
+                                 ,op
+                                 :infinite-x-finite-y
+                                 (,op x (coerce 0 '(dispatch-type x)))
+                                 :infinite-y-finite-x
+                                 (,op (coerce 0 '(dispatch-type y)) y))
+                                (((foreach fixnum bignum) ratio)
+                                 (,op x (,ratio-arg2 (numerator y)
+                                                     (denominator y))))
+                                ((ratio integer)
+                                 (,op (,ratio-arg1 (numerator x)
+                                                   (denominator x))
+                                      y))
+                                ((ratio ratio)
+                                 (,op (* (numerator   (truly-the ratio x))
+                                         (denominator (truly-the ratio y)))
+                                      (* (numerator   (truly-the ratio y))
+                                         (denominator (truly-the ratio x)))))
+                                ,@cases))))
+  (def-two-arg-</> two-arg-< < floor ceiling
+    ((fixnum bignum)
+     (bignum-plus-p y))
+    ((bignum fixnum)
+     (not (bignum-plus-p x)))
+    ((bignum bignum)
+     (minusp (bignum-compare x y))))
+  (def-two-arg-</> two-arg-> > ceiling floor
+    ((fixnum bignum)
+     (not (bignum-plus-p y)))
+    ((bignum fixnum)
+     (bignum-plus-p x))
+    ((bignum bignum)
+     (plusp (bignum-compare x y)))))
+
+(defun two-arg-= (x y)
+  (number-dispatch ((x number) (y number))
+    (basic-compare =
+                  ;; An infinite value is never equal to a finite value.
+                  :infinite-x-finite-y nil
+                  :infinite-y-finite-x nil)
+    ((fixnum (or bignum ratio)) nil)
+
+    ((bignum (or fixnum ratio)) nil)
+    ((bignum bignum)
+     (zerop (bignum-compare x y)))
+
+    ((ratio integer) nil)
+    ((ratio ratio)
+     (and (eql (numerator x) (numerator y))
+         (eql (denominator x) (denominator y))))
+
+    ((complex complex)
+     (and (= (realpart x) (realpart y))
+         (= (imagpart x) (imagpart y))))
+    (((foreach fixnum bignum ratio single-float double-float
+              #!+long-float long-float) complex)
+     (and (= x (realpart y))
+         (zerop (imagpart y))))
+    ((complex (or float rational))
+     (and (= (realpart x) y)
+         (zerop (imagpart x))))))
+
+(defun eql (obj1 obj2)
+  #!+sb-doc
+  "Return T if OBJ1 and OBJ2 represent the same object, otherwise NIL."
+  (or (eq obj1 obj2)
+      (if (or (typep obj2 'fixnum)
+             (not (typep obj2 'number)))
+         nil
+         (macrolet ((foo (&rest stuff)
+                      `(typecase obj2
+                         ,@(mapcar #'(lambda (foo)
+                                       (let ((type (car foo))
+                                             (fn (cadr foo)))
+                                         `(,type
+                                           (and (typep obj1 ',type)
+                                                (,fn obj1 obj2)))))
+                                   stuff))))
+           (foo
+             (single-float eql)
+             (double-float eql)
+             #!+long-float
+             (long-float eql)
+             (bignum
+              (lambda (x y)
+                (zerop (bignum-compare x y))))
+             (ratio
+              (lambda (x y)
+                (and (eql (numerator x) (numerator y))
+                     (eql (denominator x) (denominator y)))))
+             (complex
+              (lambda (x y)
+                (and (eql (realpart x) (realpart y))
+                     (eql (imagpart x) (imagpart y))))))))))
+\f
+;;;; logicals
+
+(defun logior (&rest integers)
+  #!+sb-doc
+  "Returns the bit-wise or of its arguments. Args must be integers."
+  (declare (list integers))
+  (if integers
+      (do ((result (pop integers) (logior result (pop integers))))
+         ((null integers) result))
+      0))
+
+(defun logxor (&rest integers)
+  #!+sb-doc
+  "Returns the bit-wise exclusive or of its arguments. Args must be integers."
+  (declare (list integers))
+  (if integers
+      (do ((result (pop integers) (logxor result (pop integers))))
+         ((null integers) result))
+      0))
+
+(defun logand (&rest integers)
+  #!+sb-doc
+  "Returns the bit-wise and of its arguments. Args must be integers."
+  (declare (list integers))
+  (if integers
+      (do ((result (pop integers) (logand result (pop integers))))
+         ((null integers) result))
+      -1))
+
+(defun logeqv (&rest integers)
+  #!+sb-doc
+  "Returns the bit-wise equivalence of its arguments. Args must be integers."
+  (declare (list integers))
+  (if integers
+      (do ((result (pop integers) (logeqv result (pop integers))))
+         ((null integers) result))
+      -1))
+
+(defun lognand (integer1 integer2)
+  #!+sb-doc
+  "Returns the complement of the logical AND of integer1 and integer2."
+  (lognand integer1 integer2))
+
+(defun lognor (integer1 integer2)
+  #!+sb-doc
+  "Returns the complement of the logical OR of integer1 and integer2."
+  (lognor integer1 integer2))
+
+(defun logandc1 (integer1 integer2)
+  #!+sb-doc
+  "Returns the logical AND of (LOGNOT integer1) and integer2."
+  (logandc1 integer1 integer2))
+
+(defun logandc2 (integer1 integer2)
+  #!+sb-doc
+  "Returns the logical AND of integer1 and (LOGNOT integer2)."
+  (logandc2 integer1 integer2))
+
+(defun logorc1 (integer1 integer2)
+  #!+sb-doc
+  "Returns the logical OR of (LOGNOT integer1) and integer2."
+  (logorc1 integer1 integer2))
+
+(defun logorc2 (integer1 integer2)
+  #!+sb-doc
+  "Returns the logical OR of integer1 and (LOGNOT integer2)."
+  (logorc2 integer1 integer2))
+
+(defun lognot (number)
+  #!+sb-doc
+  "Returns the bit-wise logical not of integer."
+  (etypecase number
+    (fixnum (lognot (truly-the fixnum number)))
+    (bignum (bignum-logical-not number))))
+
+(macrolet ((def-frob (name op big-op)
+            `(defun ,name (x y)
+              (number-dispatch ((x integer) (y integer))
+                (bignum-cross-fixnum ,op ,big-op)))))
+  (def-frob two-arg-and logand bignum-logical-and)
+  (def-frob two-arg-ior logior bignum-logical-ior)
+  (def-frob two-arg-xor logxor bignum-logical-xor))
+
+(defun logcount (integer)
+  #!+sb-doc
+  "Count the number of 1 bits if INTEGER is positive, and the number of 0 bits
+  if INTEGER is negative."
+  (etypecase integer
+    (fixnum
+     (logcount (truly-the (integer 0 #.(max most-positive-fixnum
+                                           (lognot most-negative-fixnum)))
+                         (if (minusp (truly-the fixnum integer))
+                             (lognot (truly-the fixnum integer))
+                             integer))))
+    (bignum
+     (bignum-logcount integer))))
+
+(defun logtest (integer1 integer2)
+  #!+sb-doc
+  "Predicate which returns T if logand of integer1 and integer2 is not zero."
+  (logtest integer1 integer2))
+
+(defun logbitp (index integer)
+  #!+sb-doc
+  "Predicate returns T if bit index of integer is a 1."
+  (logbitp index integer))
+
+(defun ash (integer count)
+  #!+sb-doc
+  "Shifts integer left by count places preserving sign. - count shifts right."
+  (declare (integer integer count))
+  (etypecase integer
+    (fixnum
+     (cond ((zerop integer)
+           0)
+          ((fixnump count)
+           (let ((length (integer-length (truly-the fixnum integer)))
+                 (count (truly-the fixnum count)))
+             (declare (fixnum length count))
+             (cond ((and (plusp count)
+                         (> (+ length count)
+                            (integer-length most-positive-fixnum)))
+                    (bignum-ashift-left (make-small-bignum integer) count))
+                   (t
+                    (truly-the fixnum
+                               (ash (truly-the fixnum integer) count))))))
+          ((minusp count)
+           (if (minusp integer) -1 0))
+          (t
+           (bignum-ashift-left (make-small-bignum integer) count))))
+    (bignum
+     (if (plusp count)
+        (bignum-ashift-left integer count)
+        (bignum-ashift-right integer (- count))))))
+
+(defun integer-length (integer)
+  #!+sb-doc
+  "Returns the number of significant bits in the absolute value of integer."
+  (etypecase integer
+    (fixnum
+     (integer-length (truly-the fixnum integer)))
+    (bignum
+     (bignum-integer-length integer))))
+\f
+;;;; BYTE, bytespecs, and related operations
+
+(defun byte (size position)
+  #!+sb-doc
+  "Returns a byte specifier which may be used by other byte functions."
+  (byte size position))
+
+(defun byte-size (bytespec)
+  #!+sb-doc
+  "Returns the size part of the byte specifier bytespec."
+  (byte-size bytespec))
+
+(defun byte-position (bytespec)
+  #!+sb-doc
+  "Returns the position part of the byte specifier bytespec."
+  (byte-position bytespec))
+
+(defun ldb (bytespec integer)
+  #!+sb-doc
+  "Extract the specified byte from integer, and right justify result."
+  (ldb bytespec integer))
+
+(defun ldb-test (bytespec integer)
+  #!+sb-doc
+  "Returns T if any of the specified bits in integer are 1's."
+  (ldb-test bytespec integer))
+
+(defun mask-field (bytespec integer)
+  #!+sb-doc
+  "Extract the specified byte from integer,  but do not right justify result."
+  (mask-field bytespec integer))
+
+(defun dpb (newbyte bytespec integer)
+  #!+sb-doc
+  "Returns new integer with newbyte in specified position, newbyte is right justified."
+  (dpb newbyte bytespec integer))
+
+(defun deposit-field (newbyte bytespec integer)
+  #!+sb-doc
+  "Returns new integer with newbyte in specified position, newbyte is not right justified."
+  (deposit-field newbyte bytespec integer))
+
+(defun %ldb (size posn integer)
+  (logand (ash integer (- posn))
+         (1- (ash 1 size))))
+
+(defun %mask-field (size posn integer)
+  (logand integer (ash (1- (ash 1 size)) posn)))
+
+(defun %dpb (newbyte size posn integer)
+  (let ((mask (1- (ash 1 size))))
+    (logior (logand integer (lognot (ash mask posn)))
+           (ash (logand newbyte mask) posn))))
+
+(defun %deposit-field (newbyte size posn integer)
+  (let ((mask (ash (ldb (byte size 0) -1) posn)))
+    (logior (logand newbyte mask)
+           (logand integer (lognot mask)))))
+\f
+;;;; BOOLE
+
+;;; The boole function dispaches to any logic operation depending on
+;;;     the value of a variable. Presently, legal selector values are [0..15].
+;;;     boole is open coded for calls with a constant selector. or with calls
+;;;     using any of the constants declared below.
+
+(defconstant boole-clr 0
+  #!+sb-doc
+  "Boole function op, makes BOOLE return 0.")
+
+(defconstant boole-set 1
+  #!+sb-doc
+  "Boole function op, makes BOOLE return -1.")
+
+(defconstant boole-1   2
+  #!+sb-doc
+  "Boole function op, makes BOOLE return integer1.")
+
+(defconstant boole-2   3
+  #!+sb-doc
+  "Boole function op, makes BOOLE return integer2.")
+
+(defconstant boole-c1  4
+  #!+sb-doc
+  "Boole function op, makes BOOLE return complement of integer1.")
+
+(defconstant boole-c2  5
+  #!+sb-doc
+  "Boole function op, makes BOOLE return complement of integer2.")
+
+(defconstant boole-and 6
+  #!+sb-doc
+  "Boole function op, makes BOOLE return logand of integer1 and integer2.")
+
+(defconstant boole-ior 7
+  #!+sb-doc
+  "Boole function op, makes BOOLE return logior of integer1 and integer2.")
+
+(defconstant boole-xor 8
+  #!+sb-doc
+  "Boole function op, makes BOOLE return logxor of integer1 and integer2.")
+
+(defconstant boole-eqv 9
+  #!+sb-doc
+  "Boole function op, makes BOOLE return logeqv of integer1 and integer2.")
+
+(defconstant boole-nand  10
+  #!+sb-doc
+  "Boole function op, makes BOOLE return log nand of integer1 and integer2.")
+
+(defconstant boole-nor   11
+  #!+sb-doc
+  "Boole function op, makes BOOLE return lognor of integer1 and integer2.")
+
+(defconstant boole-andc1 12
+  #!+sb-doc
+  "Boole function op, makes BOOLE return logandc1 of integer1 and integer2.")
+
+(defconstant boole-andc2 13
+  #!+sb-doc
+  "Boole function op, makes BOOLE return logandc2 of integer1 and integer2.")
+
+(defconstant boole-orc1  14
+  #!+sb-doc
+  "Boole function op, makes BOOLE return logorc1 of integer1 and integer2.")
+
+(defconstant boole-orc2  15
+  #!+sb-doc
+  "Boole function op, makes BOOLE return logorc2 of integer1 and integer2.")
+
+(defun boole (op integer1 integer2)
+  #!+sb-doc
+  "Bit-wise boolean function on two integers. Function chosen by OP:
+       0       BOOLE-CLR
+       1       BOOLE-SET
+       2       BOOLE-1
+       3       BOOLE-2
+       4       BOOLE-C1
+       5       BOOLE-C2
+       6       BOOLE-AND
+       7       BOOLE-IOR
+       8       BOOLE-XOR
+       9       BOOLE-EQV
+       10      BOOLE-NAND
+       11      BOOLE-NOR
+       12      BOOLE-ANDC1
+       13      BOOLE-ANDC2
+       14      BOOLE-ORC1
+       15      BOOLE-ORC2"
+  (case op
+    (0 (boole 0 integer1 integer2))
+    (1 (boole 1 integer1 integer2))
+    (2 (boole 2 integer1 integer2))
+    (3 (boole 3 integer1 integer2))
+    (4 (boole 4 integer1 integer2))
+    (5 (boole 5 integer1 integer2))
+    (6 (boole 6 integer1 integer2))
+    (7 (boole 7 integer1 integer2))
+    (8 (boole 8 integer1 integer2))
+    (9 (boole 9 integer1 integer2))
+    (10 (boole 10 integer1 integer2))
+    (11 (boole 11 integer1 integer2))
+    (12 (boole 12 integer1 integer2))
+    (13 (boole 13 integer1 integer2))
+    (14 (boole 14 integer1 integer2))
+    (15 (boole 15 integer1 integer2))
+    (t (error "~S is not of type (mod 16)." op))))
+\f
+;;;; GCD and LCM
+
+(defun gcd (&rest numbers)
+  #!+sb-doc
+  "Returns the greatest common divisor of the arguments, which must be
+  integers. Gcd with no arguments is defined to be 0."
+  (cond ((null numbers) 0)
+       ((null (cdr numbers)) (abs (the integer (car numbers))))
+       (t
+        (do ((gcd (the integer (car numbers))
+                  (gcd gcd (the integer (car rest))))
+             (rest (cdr numbers) (cdr rest)))
+            ((null rest) gcd)
+          (declare (integer gcd)
+                   (list rest))))))
+
+(defun lcm (&rest numbers)
+  #!+sb-doc
+  "Returns the least common multiple of one or more integers. LCM of no
+  arguments is defined to be 1."
+  (cond ((null numbers) 1)
+       ((null (cdr numbers)) (abs (the integer (car numbers))))
+       (t
+        (do ((lcm (the integer (car numbers))
+                  (lcm lcm (the integer (car rest))))
+             (rest (cdr numbers) (cdr rest)))
+            ((null rest) lcm)
+          (declare (integer lcm) (list rest))))))
+
+(defun two-arg-lcm (n m)
+  (declare (integer n m))
+  (* (truncate (max n m) (gcd n m)) (min n m)))
+
+;;; Do the GCD of two integer arguments. With fixnum arguments, we use the
+;;; binary GCD algorithm from Knuth's seminumerical algorithms (slightly
+;;; structurified), otherwise we call BIGNUM-GCD. We pick off the special case
+;;; of 0 before the dispatch so that the bignum code doesn't have to worry
+;;; about "small bignum" zeros.
+(defun two-arg-gcd (u v)
+  (cond ((eql u 0) v)
+       ((eql v 0) u)
+       (t
+        (number-dispatch ((u integer) (v integer))
+          ((fixnum fixnum)
+           (locally
+             (declare (optimize (speed 3) (safety 0)))
+             (do ((k 0 (1+ k))
+                  (u (abs u) (ash u -1))
+                  (v (abs v) (ash v -1)))
+                 ((oddp (logior u v))
+                  (do ((temp (if (oddp u) (- v) (ash u -1))
+                             (ash temp -1)))
+                      (nil)
+                    (declare (fixnum temp))
+                    (when (oddp temp)
+                      (if (plusp temp)
+                          (setq u temp)
+                          (setq v (- temp)))
+                      (setq temp (- u v))
+                      (when (zerop temp)
+                        (let ((res (ash u k)))
+                          (declare (type (signed-byte 31) res)
+                                   (optimize (inhibit-warnings 3)))
+                          (return res))))))
+               (declare (type (mod 30) k)
+                        (type (signed-byte 31) u v)))))
+          ((bignum bignum)
+           (bignum-gcd u v))
+          ((bignum fixnum)
+           (bignum-gcd u (make-small-bignum v)))
+          ((fixnum bignum)
+           (bignum-gcd (make-small-bignum u) v))))))
+\f
+;;; From discussion on comp.lang.lisp and Akira Kurihara.
+(defun isqrt (n)
+  #!+sb-doc
+  "Returns the root of the nearest integer less than n which is a perfect
+   square."
+  (declare (type unsigned-byte n) (values unsigned-byte))
+  ;; Theoretically (> n 7), i.e., n-len-quarter > 0.
+  (if (and (fixnump n) (<= n 24))
+      (cond ((> n 15) 4)
+           ((> n  8) 3)
+           ((> n  3) 2)
+           ((> n  0) 1)
+           (t 0))
+      (let* ((n-len-quarter (ash (integer-length n) -2))
+            (n-half (ash n (- (ash n-len-quarter 1))))
+            (n-half-isqrt (isqrt n-half))
+            (init-value (ash (1+ n-half-isqrt) n-len-quarter)))
+       (loop
+         (let ((iterated-value
+                (ash (+ init-value (truncate n init-value)) -1)))
+           (unless (< iterated-value init-value)
+             (return init-value))
+           (setq init-value iterated-value))))))
+\f
+;;;; miscellaneous number predicates
+
+(macrolet ((def-frob (name doc)
+            `(defun ,name (number) ,doc (,name number))))
+  (def-frob zerop "Returns T if number = 0, NIL otherwise.")
+  (def-frob plusp "Returns T if number > 0, NIL otherwise.")
+  (def-frob minusp "Returns T if number < 0, NIL otherwise.")
+  (def-frob oddp "Returns T if number is odd, NIL otherwise.")
+  (def-frob evenp "Returns T if number is even, NIL otherwise."))
index c24892f..a430f42 100644 (file)
@@ -25,6 +25,9 @@
   (unparse-enough (required-argument) :type function)
   (customary-case (required-argument) :type (member :upper :lower)))
 
+(def!method print-object ((host host) stream)
+  (print-unreadable-object (host stream :type t :identity t)))
+
 (def!struct (logical-host
             (:make-load-form-fun make-logical-host-load-form-fun)
             (:include host
   ;; on standard Unix filesystems)
   (version nil :type (or integer pathname-component-tokens (member :newest))))
 
-;;; Return a value suitable, e.g., for preinitializing
-;;; *DEFAULT-PATHNAME-DEFAULTS* before *DEFAULT-PATHNAME-DEFAULTS* is
-;;; initialized (at which time we can't safely call e.g. #'PATHNAME).
-(defun make-trivial-default-pathname ()
-  (%make-pathname *unix-host* nil nil nil nil :newest))
-
 ;;; Logical pathnames have the following format:
 ;;;
 ;;; logical-namestring ::=
diff --git a/src/code/target-numbers.lisp b/src/code/target-numbers.lisp
deleted file mode 100644 (file)
index aa7304a..0000000
+++ /dev/null
@@ -1,1323 +0,0 @@
-;;;; This file contains the definitions of most number 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!KERNEL")
-\f
-;;;; the NUMBER-DISPATCH macro
-
-(eval-when (:compile-toplevel :load-toplevel :execute)
-
-;;; Grovel an individual case to NUMBER-DISPATCH, augmenting RESULT
-;;; with the type dispatches and bodies. Result is a tree built of
-;;; alists representing the dispatching off each arg (in order). The
-;;; leaf is the body to be executed in that case.
-(defun parse-number-dispatch (vars result types var-types body)
-  (cond ((null vars)
-        (unless (null types) (error "More types than vars."))
-        (when (cdr result)
-          (error "Duplicate case: ~S." body))
-        (setf (cdr result)
-              (sublis var-types body :test #'equal)))
-       ((null types)
-        (error "More vars than types."))
-       (t
-        (flet ((frob (var type)
-                 (parse-number-dispatch
-                  (rest vars)
-                  (or (assoc type (cdr result) :test #'equal)
-                      (car (setf (cdr result)
-                                 (acons type nil (cdr result)))))
-                  (rest types)
-                  (acons `(dispatch-type ,var) type var-types)
-                  body)))
-          (let ((type (first types))
-                (var (first vars)))
-            (if (and (consp type) (eq (first type) 'foreach))
-                (dolist (type (rest type))
-                  (frob var type))
-                (frob var type)))))))
-
-;;; our guess for the preferred order in which to do type tests
-;;; (cheaper and/or more probable first.)
-(defparameter *type-test-ordering*
-  '(fixnum single-float double-float integer #!+long-float long-float bignum
-    complex ratio))
-
-;;; Should TYPE1 be tested before TYPE2?
-(defun type-test-order (type1 type2)
-  (let ((o1 (position type1 *type-test-ordering*))
-       (o2 (position type2 *type-test-ordering*)))
-    (cond ((not o1) nil)
-         ((not o2) t)
-         (t
-          (< o1 o2)))))
-
-;;; Return an ETYPECASE form that does the type dispatch, ordering the
-;;; cases for efficiency.
-(defun generate-number-dispatch (vars error-tags cases)
-  (if vars
-      (let ((var (first vars))
-           (cases (sort cases #'type-test-order :key #'car)))
-       `((typecase ,var
-           ,@(mapcar #'(lambda (case)
-                         `(,(first case)
-                           ,@(generate-number-dispatch (rest vars)
-                                                       (rest error-tags)
-                                                       (cdr case))))
-                     cases)
-           (t (go ,(first error-tags))))))
-      cases))
-
-) ; EVAL-WHEN
-
-;;; This is a vaguely case-like macro that does number cross-product
-;;; dispatches. The Vars are the variables we are dispatching off of.
-;;; The Type paired with each Var is used in the error message when no
-;;; case matches. Each case specifies a Type for each var, and is
-;;; executed when that signature holds. A type may be a list
-;;; (FOREACH Each-Type*), causing that case to be repeatedly
-;;; instantiated for every Each-Type. In the body of each case, any
-;;; list of the form (DISPATCH-TYPE Var-Name) is substituted with the
-;;; type of that var in that instance of the case.
-;;;
-;;; As an alternate to a case spec, there may be a form whose CAR is a
-;;; symbol. In this case, we apply the CAR of the form to the CDR and
-;;; treat the result of the call as a list of cases. This process is
-;;; not applied recursively.
-(defmacro number-dispatch (var-specs &body cases)
-  (let ((res (list nil))
-       (vars (mapcar #'car var-specs))
-       (block (gensym)))
-    (dolist (case cases)
-      (if (symbolp (first case))
-         (let ((cases (apply (symbol-function (first case)) (rest case))))
-           (dolist (case cases)
-             (parse-number-dispatch vars res (first case) nil (rest case))))
-         (parse-number-dispatch vars res (first case) nil (rest case))))
-
-    (collect ((errors)
-             (error-tags))
-      (dolist (spec var-specs)
-       (let ((var (first spec))
-             (type (second spec))
-             (tag (gensym)))
-         (error-tags tag)
-         (errors tag)
-         (errors `(return-from
-                   ,block
-                   (error 'simple-type-error :datum ,var
-                          :expected-type ',type
-                          :format-control
-                          "~@<Argument ~A is not a ~S: ~2I~_~S~:>"
-                          :format-arguments
-                          (list ',var ',type ,var))))))
-
-      `(block ,block
-        (tagbody
-          (return-from ,block
-                       ,@(generate-number-dispatch vars (error-tags)
-                                                   (cdr res)))
-          ,@(errors))))))
-\f
-;;;; binary operation dispatching utilities
-
-(eval-when (:compile-toplevel :execute)
-
-;;; Return NUMBER-DISPATCH forms for rational X float.
-(defun float-contagion (op x y &optional (rat-types '(fixnum bignum ratio)))
-  `(((single-float single-float) (,op ,x ,y))
-    (((foreach ,@rat-types)
-      (foreach single-float double-float #!+long-float long-float))
-     (,op (coerce ,x '(dispatch-type ,y)) ,y))
-    (((foreach single-float double-float #!+long-float long-float)
-      (foreach ,@rat-types))
-     (,op ,x (coerce ,y '(dispatch-type ,x))))
-    #!+long-float
-    (((foreach single-float double-float long-float) long-float)
-     (,op (coerce ,x 'long-float) ,y))
-    #!+long-float
-    ((long-float (foreach single-float double-float))
-     (,op ,x (coerce ,y 'long-float)))
-    (((foreach single-float double-float) double-float)
-     (,op (coerce ,x 'double-float) ,y))
-    ((double-float single-float)
-     (,op ,x (coerce ,y 'double-float)))))
-
-;;; Return NUMBER-DISPATCH forms for bignum X fixnum.
-(defun bignum-cross-fixnum (fix-op big-op)
-  `(((fixnum fixnum) (,fix-op x y))
-    ((fixnum bignum)
-     (,big-op (make-small-bignum x) y))
-    ((bignum fixnum)
-     (,big-op x (make-small-bignum y)))
-    ((bignum bignum)
-     (,big-op x y))))
-
-) ; EVAL-WHEN
-\f
-;;;; canonicalization utilities
-
-;;; If IMAGPART is 0, return REALPART, otherwise make a complex. This is
-;;; used when we know that REALPART and IMAGPART are the same type, but
-;;; rational canonicalization might still need to be done.
-#!-sb-fluid (declaim (inline canonical-complex))
-(defun canonical-complex (realpart imagpart)
-  (if (eql imagpart 0)
-      realpart
-      (cond #!+long-float
-           ((and (typep realpart 'long-float)
-                 (typep imagpart 'long-float))
-            (truly-the (complex long-float) (complex realpart imagpart)))
-           ((and (typep realpart 'double-float)
-                 (typep imagpart 'double-float))
-            (truly-the (complex double-float) (complex realpart imagpart)))
-           ((and (typep realpart 'single-float)
-                 (typep imagpart 'single-float))
-            (truly-the (complex single-float) (complex realpart imagpart)))
-           (t
-            (%make-complex realpart imagpart)))))
-
-;;; Given a numerator and denominator with the GCD already divided
-;;; out, make a canonical rational. We make the denominator positive,
-;;; and check whether it is 1.
-#!-sb-fluid (declaim (inline build-ratio))
-(defun build-ratio (num den)
-  (multiple-value-bind (num den)
-      (if (minusp den)
-         (values (- num) (- den))
-         (values num den))
-    (if (eql den 1)
-       num
-       (%make-ratio num den))))
-
-;;; Truncate X and Y, but bum the case where Y is 1.
-#!-sb-fluid (declaim (inline maybe-truncate))
-(defun maybe-truncate (x y)
-  (if (eql y 1)
-      x
-      (truncate x y)))
-\f
-;;;; COMPLEXes
-
-(defun upgraded-complex-part-type (spec)
-  #!+sb-doc
-  "Returns the element type of the most specialized COMPLEX number type that
-   can hold parts of type SPEC."
-  (cond ((unknown-type-p (specifier-type spec))
-        (error "undefined type: ~S" spec))
-       ((subtypep spec 'single-float)
-        'single-float)
-       ((subtypep spec 'double-float)
-        'double-float)
-       #!+long-float
-       ((subtypep spec 'long-float)
-        'long-float)
-       ((subtypep spec 'rational)
-        'rational)
-       (t
-        'real)))
-
-(defun complex (realpart &optional (imagpart 0))
-  #!+sb-doc
-  "Builds a complex number from the specified components."
-  (flet ((%%make-complex (realpart imagpart)
-          (cond #!+long-float
-                ((and (typep realpart 'long-float)
-                      (typep imagpart 'long-float))
-                 (truly-the (complex long-float)
-                            (complex realpart imagpart)))
-                ((and (typep realpart 'double-float)
-                      (typep imagpart 'double-float))
-                 (truly-the (complex double-float)
-                            (complex realpart imagpart)))
-                ((and (typep realpart 'single-float)
-                      (typep imagpart 'single-float))
-                 (truly-the (complex single-float)
-                            (complex realpart imagpart)))
-                (t
-                 (%make-complex realpart imagpart)))))
-  (number-dispatch ((realpart real) (imagpart real))
-    ((rational rational)
-     (canonical-complex realpart imagpart))
-    (float-contagion %%make-complex realpart imagpart (rational)))))
-
-(defun realpart (number)
-  #!+sb-doc
-  "Extracts the real part of a number."
-  (typecase number
-    #!+long-float
-    ((complex long-float)
-     (truly-the long-float (realpart number)))
-    ((complex double-float)
-     (truly-the double-float (realpart number)))
-    ((complex single-float)
-     (truly-the single-float (realpart number)))
-    ((complex rational)
-     (sb!kernel:%realpart number))
-    (t
-     number)))
-
-(defun imagpart (number)
-  #!+sb-doc
-  "Extracts the imaginary part of a number."
-  (typecase number
-    #!+long-float
-    ((complex long-float)
-     (truly-the long-float (imagpart number)))
-    ((complex double-float)
-     (truly-the double-float (imagpart number)))
-    ((complex single-float)
-     (truly-the single-float (imagpart number)))
-    ((complex rational)
-     (sb!kernel:%imagpart number))
-    (float
-     (float 0 number))
-    (t
-     0)))
-
-(defun conjugate (number)
-  #!+sb-doc
-  "Returns the complex conjugate of NUMBER. For non-complex numbers, this is
-  an identity."
-  (if (complexp number)
-      (complex (realpart number) (- (imagpart number)))
-      number))
-
-(defun signum (number)
-  #!+sb-doc
-  "If NUMBER is zero, return NUMBER, else return (/ NUMBER (ABS NUMBER))."
-  (if (zerop number)
-      number
-      (if (rationalp number)
-         (if (plusp number) 1 -1)
-         (/ number (abs number)))))
-\f
-;;;; ratios
-
-(defun numerator (number)
-  #!+sb-doc
-  "Return the numerator of NUMBER, which must be rational."
-  (numerator number))
-
-(defun denominator (number)
-  #!+sb-doc
-  "Return the denominator of NUMBER, which must be rational."
-  (denominator number))
-\f
-;;;; arithmetic operations
-
-(macrolet ((define-arith (op init doc)
-            #!-sb-doc (declare (ignore doc))
-            `(defun ,op (&rest args)
-               #!+sb-doc ,doc
-               (if (null args) ,init
-                 (do ((args (cdr args) (cdr args))
-                      (res (car args) (,op res (car args))))
-                     ((null args) res))))))
-  (define-arith + 0
-    "Returns the sum of its arguments. With no args, returns 0.")
-  (define-arith * 1
-    "Returns the product of its arguments. With no args, returns 1."))
-
-(defun - (number &rest more-numbers)
-  #!+sb-doc
-  "Subtracts the second and all subsequent arguments from the first.
-  With one arg, negates it."
-  (if more-numbers
-      (do ((nlist more-numbers (cdr nlist))
-          (result number))
-         ((atom nlist) result)
-        (declare (list nlist))
-        (setq result (- result (car nlist))))
-      (- number)))
-
-(defun / (number &rest more-numbers)
-  #!+sb-doc
-  "Divide the first argument by each of the following arguments, in turn.
-  With one argument, return reciprocal."
-  (if more-numbers
-      (do ((nlist more-numbers (cdr nlist))
-          (result number))
-         ((atom nlist) result)
-        (declare (list nlist))
-        (setq result (/ result (car nlist))))
-      (/ number)))
-
-(defun 1+ (number)
-  #!+sb-doc
-  "Returns NUMBER + 1."
-  (1+ number))
-
-(defun 1- (number)
-  #!+sb-doc
-  "Returns NUMBER - 1."
-  (1- number))
-
-(eval-when (:compile-toplevel)
-
-(sb!xc:defmacro two-arg-+/- (name op big-op)
-  `(defun ,name (x y)
-     (number-dispatch ((x number) (y number))
-       (bignum-cross-fixnum ,op ,big-op)
-       (float-contagion ,op x y)
-
-       ((complex complex)
-       (canonical-complex (,op (realpart x) (realpart y))
-                          (,op (imagpart x) (imagpart y))))
-       (((foreach bignum fixnum ratio single-float double-float
-                 #!+long-float long-float) complex)
-       (complex (,op x (realpart y)) (,op (imagpart y))))
-       ((complex (or rational float))
-       (complex (,op (realpart x) y) (imagpart x)))
-
-       (((foreach fixnum bignum) ratio)
-       (let* ((dy (denominator y))
-              (n (,op (* x dy) (numerator y))))
-         (%make-ratio n dy)))
-       ((ratio integer)
-       (let* ((dx (denominator x))
-              (n (,op (numerator x) (* y dx))))
-         (%make-ratio n dx)))
-       ((ratio ratio)
-       (let* ((nx (numerator x))
-              (dx (denominator x))
-              (ny (numerator y))
-              (dy (denominator y))
-              (g1 (gcd dx dy)))
-         (if (eql g1 1)
-             (%make-ratio (,op (* nx dy) (* dx ny)) (* dx dy))
-             (let* ((t1 (,op (* nx (truncate dy g1)) (* (truncate dx g1) ny)))
-                    (g2 (gcd t1 g1))
-                    (t2 (truncate dx g1)))
-               (cond ((eql t1 0) 0)
-                     ((eql g2 1)
-                      (%make-ratio t1 (* t2 dy)))
-                     (T (let* ((nn (truncate t1 g2))
-                               (t3 (truncate dy g2))
-                               (nd (if (eql t2 1) t3 (* t2 t3))))
-                          (if (eql nd 1) nn (%make-ratio nn nd))))))))))))
-
-); Eval-When (Compile)
-
-(two-arg-+/- two-arg-+ + add-bignums)
-(two-arg-+/- two-arg-- - subtract-bignum)
-
-(defun two-arg-* (x y)
-  (flet ((integer*ratio (x y)
-          (if (eql x 0) 0
-              (let* ((ny (numerator y))
-                     (dy (denominator y))
-                     (gcd (gcd x dy)))
-                (if (eql gcd 1)
-                    (%make-ratio (* x ny) dy)
-                    (let ((nn (* (truncate x gcd) ny))
-                          (nd (truncate dy gcd)))
-                      (if (eql nd 1)
-                          nn
-                          (%make-ratio nn nd)))))))
-        (complex*real (x y)
-          (canonical-complex (* (realpart x) y) (* (imagpart x) y))))
-    (number-dispatch ((x number) (y number))
-      (float-contagion * x y)
-
-      ((fixnum fixnum) (multiply-fixnums x y))
-      ((bignum fixnum) (multiply-bignum-and-fixnum x y))
-      ((fixnum bignum) (multiply-bignum-and-fixnum y x))
-      ((bignum bignum) (multiply-bignums x y))
-
-      ((complex complex)
-       (let* ((rx (realpart x))
-             (ix (imagpart x))
-             (ry (realpart y))
-             (iy (imagpart y)))
-        (canonical-complex (- (* rx ry) (* ix iy)) (+ (* rx iy) (* ix ry)))))
-      (((foreach bignum fixnum ratio single-float double-float
-                #!+long-float long-float)
-       complex)
-       (complex*real y x))
-      ((complex (or rational float))
-       (complex*real x y))
-
-      (((foreach bignum fixnum) ratio) (integer*ratio x y))
-      ((ratio integer) (integer*ratio y x))
-      ((ratio ratio)
-       (let* ((nx (numerator x))
-             (dx (denominator x))
-             (ny (numerator y))
-             (dy (denominator y))
-             (g1 (gcd nx dy))
-             (g2 (gcd dx ny)))
-        (build-ratio (* (maybe-truncate nx g1)
-                        (maybe-truncate ny g2))
-                     (* (maybe-truncate dx g2)
-                        (maybe-truncate dy g1))))))))
-
-;;; Divide two integers, producing a canonical rational. If a fixnum,
-;;; we see whether they divide evenly before trying the GCD. In the
-;;; bignum case, we don't bother, since bignum division is expensive,
-;;; and the test is not very likely to succeed.
-(defun integer-/-integer (x y)
-  (if (and (typep x 'fixnum) (typep y 'fixnum))
-      (multiple-value-bind (quo rem) (truncate x y)
-       (if (zerop rem)
-           quo
-           (let ((gcd (gcd x y)))
-             (declare (fixnum gcd))
-             (if (eql gcd 1)
-                 (build-ratio x y)
-                 (build-ratio (truncate x gcd) (truncate y gcd))))))
-      (let ((gcd (gcd x y)))
-       (if (eql gcd 1)
-           (build-ratio x y)
-           (build-ratio (truncate x gcd) (truncate y gcd))))))
-
-(defun two-arg-/ (x y)
-  (number-dispatch ((x number) (y number))
-    (float-contagion / x y (ratio integer))
-
-    ((complex complex)
-     (let* ((rx (realpart x))
-           (ix (imagpart x))
-           (ry (realpart y))
-           (iy (imagpart y)))
-       (if (> (abs ry) (abs iy))
-          (let* ((r (/ iy ry))
-                 (dn (* ry (+ 1 (* r r)))))
-            (canonical-complex (/ (+ rx (* ix r)) dn)
-                               (/ (- ix (* rx r)) dn)))
-          (let* ((r (/ ry iy))
-                 (dn (* iy (+ 1 (* r r)))))
-            (canonical-complex (/ (+ (* rx r) ix) dn)
-                               (/ (- (* ix r) rx) dn))))))
-    (((foreach integer ratio single-float double-float) complex)
-     (let* ((ry (realpart y))
-           (iy (imagpart y)))
-       (if (> (abs ry) (abs iy))
-          (let* ((r (/ iy ry))
-                 (dn (* ry (+ 1 (* r r)))))
-            (canonical-complex (/ x dn)
-                               (/ (- (* x r)) dn)))
-          (let* ((r (/ ry iy))
-                 (dn (* iy (+ 1 (* r r)))))
-            (canonical-complex (/ (* x r) dn)
-                               (/ (- x) dn))))))
-    ((complex (or rational float))
-     (canonical-complex (/ (realpart x) y)
-                       (/ (imagpart x) y)))
-
-    ((ratio ratio)
-     (let* ((nx (numerator x))
-           (dx (denominator x))
-           (ny (numerator y))
-           (dy (denominator y))
-           (g1 (gcd nx ny))
-           (g2 (gcd dx dy)))
-       (build-ratio (* (maybe-truncate nx g1) (maybe-truncate dy g2))
-                   (* (maybe-truncate dx g2) (maybe-truncate ny g1)))))
-
-    ((integer integer)
-     (integer-/-integer x y))
-
-    ((integer ratio)
-     (if (zerop x)
-        0
-        (let* ((ny (numerator y))
-               (dy (denominator y))
-               (gcd (gcd x ny)))
-          (build-ratio (* (maybe-truncate x gcd) dy)
-                       (maybe-truncate ny gcd)))))
-
-    ((ratio integer)
-     (let* ((nx (numerator x))
-           (gcd (gcd nx y)))
-       (build-ratio (maybe-truncate nx gcd)
-                   (* (maybe-truncate y gcd) (denominator x)))))))
-
-(defun %negate (n)
-  (number-dispatch ((n number))
-    (((foreach fixnum single-float double-float #!+long-float long-float))
-     (%negate n))
-    ((bignum)
-     (negate-bignum n))
-    ((ratio)
-     (%make-ratio (- (numerator n)) (denominator n)))
-    ((complex)
-     (complex (- (realpart n)) (- (imagpart n))))))
-\f
-;;;; TRUNCATE and friends
-
-(defun truncate (number &optional (divisor 1))
-  #!+sb-doc
-  "Returns number (or number/divisor) as an integer, rounded toward 0.
-  The second returned value is the remainder."
-  (macrolet ((truncate-float (rtype)
-              `(let* ((float-div (coerce divisor ',rtype))
-                      (res (%unary-truncate (/ number float-div))))
-                 (values res
-                         (- number
-                            (* (coerce res ',rtype) float-div))))))
-    (number-dispatch ((number real) (divisor real))
-      ((fixnum fixnum) (truncate number divisor))
-      (((foreach fixnum bignum) ratio)
-       (let ((q (truncate (* number (denominator divisor))
-                         (numerator divisor))))
-        (values q (- number (* q divisor)))))
-      ((fixnum bignum)
-       (values 0 number))
-      ((ratio (or float rational))
-       (let ((q (truncate (numerator number)
-                         (* (denominator number) divisor))))
-        (values q (- number (* q divisor)))))
-      ((bignum fixnum)
-       (bignum-truncate number (make-small-bignum divisor)))
-      ((bignum bignum)
-       (bignum-truncate number divisor))
-
-      (((foreach single-float double-float #!+long-float long-float)
-       (or rational single-float))
-       (if (eql divisor 1)
-          (let ((res (%unary-truncate number)))
-            (values res (- number (coerce res '(dispatch-type number)))))
-          (truncate-float (dispatch-type number))))
-      #!+long-float
-      ((long-float (or single-float double-float long-float))
-       (truncate-float long-float))
-      #!+long-float
-      (((foreach double-float single-float) long-float)
-       (truncate-float long-float))
-      ((double-float (or single-float double-float))
-       (truncate-float double-float))
-      ((single-float double-float)
-       (truncate-float double-float))
-      (((foreach fixnum bignum ratio)
-       (foreach single-float double-float #!+long-float long-float))
-       (truncate-float (dispatch-type divisor))))))
-
-;;; Declare these guys inline to let them get optimized a little.
-;;; ROUND and FROUND are not declared inline since they seem too
-;;; obscure and too big to inline-expand by default. Also, this gives
-;;; the compiler a chance to pick off the unary float case. Similarly,
-;;; CEILING and FLOOR are only maybe-inline for now, so that the
-;;; power-of-2 CEILING and FLOOR transforms get a chance.
-#!-sb-fluid (declaim (inline rem mod fceiling ffloor ftruncate))
-(declaim (maybe-inline ceiling floor))
-
-(defun floor (number &optional (divisor 1))
-  #!+sb-doc
-  "Returns the greatest integer not greater than number, or number/divisor.
-  The second returned value is (mod number divisor)."
-  ;; If the numbers do not divide exactly and the result of
-  ;; (/ NUMBER DIVISOR) would be negative then decrement the quotient
-  ;; and augment the remainder by the divisor.
-  (multiple-value-bind (tru rem) (truncate number divisor)
-    (if (and (not (zerop rem))
-            (if (minusp divisor)
-                (plusp number)
-                (minusp number)))
-       (values (1- tru) (+ rem divisor))
-       (values tru rem))))
-
-(defun ceiling (number &optional (divisor 1))
-  #!+sb-doc
-  "Returns the smallest integer not less than number, or number/divisor.
-  The second returned value is the remainder."
-  ;; If the numbers do not divide exactly and the result of
-  ;; (/ NUMBER DIVISOR) would be positive then increment the quotient
-  ;; and decrement the remainder by the divisor.
-  (multiple-value-bind (tru rem) (truncate number divisor)
-    (if (and (not (zerop rem))
-            (if (minusp divisor)
-                (minusp number)
-                (plusp number)))
-       (values (+ tru 1) (- rem divisor))
-       (values tru rem))))
-
-(defun round (number &optional (divisor 1))
-  #!+sb-doc
-  "Rounds number (or number/divisor) to nearest integer.
-  The second returned value is the remainder."
-  (if (eql divisor 1)
-      (round number)
-      (multiple-value-bind (tru rem) (truncate number divisor)
-       (let ((thresh (/ (abs divisor) 2)))
-         (cond ((or (> rem thresh)
-                    (and (= rem thresh) (oddp tru)))
-                (if (minusp divisor)
-                    (values (- tru 1) (+ rem divisor))
-                    (values (+ tru 1) (- rem divisor))))
-               ((let ((-thresh (- thresh)))
-                  (or (< rem -thresh)
-                      (and (= rem -thresh) (oddp tru))))
-                (if (minusp divisor)
-                    (values (+ tru 1) (- rem divisor))
-                    (values (- tru 1) (+ rem divisor))))
-               (t (values tru rem)))))))
-
-(defun rem (number divisor)
-  #!+sb-doc
-  "Returns second result of TRUNCATE."
-  (multiple-value-bind (tru rem) (truncate number divisor)
-    (declare (ignore tru))
-    rem))
-
-(defun mod (number divisor)
-  #!+sb-doc
-  "Returns second result of FLOOR."
-  (let ((rem (rem number divisor)))
-    (if (and (not (zerop rem))
-            (if (minusp divisor)
-                (plusp number)
-                (minusp number)))
-       (+ rem divisor)
-       rem)))
-
-(macrolet ((def-frob (name op doc)
-            `(defun ,name (number &optional (divisor 1))
-               ,doc
-               (multiple-value-bind (res rem) (,op number divisor)
-                 (values (float res (if (floatp rem) rem 1.0)) rem)))))
-  (def-frob ffloor floor
-    "Same as FLOOR, but returns first value as a float.")
-  (def-frob fceiling ceiling
-    "Same as CEILING, but returns first value as a float." )
-  (def-frob ftruncate truncate
-    "Same as TRUNCATE, but returns first value as a float.")
-  (def-frob fround round
-    "Same as ROUND, but returns first value as a float."))
-\f
-;;;; comparisons
-
-(defun = (number &rest more-numbers)
-  #!+sb-doc
-  "Returns T if all of its arguments are numerically equal, NIL otherwise."
-  (do ((nlist more-numbers (cdr nlist)))
-      ((atom nlist) T)
-     (declare (list nlist))
-     (if (not (= (car nlist) number)) (return nil))))
-
-(defun /= (number &rest more-numbers)
-  #!+sb-doc
-  "Returns T if no two of its arguments are numerically equal, NIL otherwise."
-  (do* ((head number (car nlist))
-       (nlist more-numbers (cdr nlist)))
-       ((atom nlist) t)
-     (declare (list nlist))
-     (unless (do* ((nl nlist (cdr nl)))
-                 ((atom nl) T)
-              (declare (list nl))
-              (if (= head (car nl)) (return nil)))
-       (return nil))))
-
-(defun < (number &rest more-numbers)
-  #!+sb-doc
-  "Returns T if its arguments are in strictly increasing order, NIL otherwise."
-  (do* ((n number (car nlist))
-       (nlist more-numbers (cdr nlist)))
-       ((atom nlist) t)
-     (declare (list nlist))
-     (if (not (< n (car nlist))) (return nil))))
-
-(defun > (number &rest more-numbers)
-  #!+sb-doc
-  "Returns T if its arguments are in strictly decreasing order, NIL otherwise."
-  (do* ((n number (car nlist))
-       (nlist more-numbers (cdr nlist)))
-       ((atom nlist) t)
-     (declare (list nlist))
-     (if (not (> n (car nlist))) (return nil))))
-
-(defun <= (number &rest more-numbers)
-  #!+sb-doc
-  "Returns T if arguments are in strictly non-decreasing order, NIL otherwise."
-  (do* ((n number (car nlist))
-       (nlist more-numbers (cdr nlist)))
-       ((atom nlist) t)
-     (declare (list nlist))
-     (if (not (<= n (car nlist))) (return nil))))
-
-(defun >= (number &rest more-numbers)
-  #!+sb-doc
-  "Returns T if arguments are in strictly non-increasing order, NIL otherwise."
-  (do* ((n number (car nlist))
-       (nlist more-numbers (cdr nlist)))
-       ((atom nlist) t)
-     (declare (list nlist))
-     (if (not (>= n (car nlist))) (return nil))))
-
-(defun max (number &rest more-numbers)
-  #!+sb-doc
-  "Returns the greatest of its arguments."
-  (do ((nlist more-numbers (cdr nlist))
-       (result number))
-      ((null nlist) (return result))
-     (declare (list nlist))
-     (if (> (car nlist) result) (setq result (car nlist)))))
-
-(defun min (number &rest more-numbers)
-  #!+sb-doc
-  "Returns the least of its arguments."
-  (do ((nlist more-numbers (cdr nlist))
-       (result number))
-      ((null nlist) (return result))
-     (declare (list nlist))
-     (if (< (car nlist) result) (setq result (car nlist)))))
-
-(eval-when (:compile-toplevel :execute)
-
-;;; The INFINITE-X-FINITE-Y and INFINITE-Y-FINITE-X args tell us how
-;;; to handle the case when X or Y is a floating-point infinity and
-;;; the other arg is a rational. (Section 12.1.4.1 of the ANSI spec
-;;; says that comparisons are done by converting the float to a
-;;; rational when comparing with a rational, but infinities can't be
-;;; converted to a rational, so we show some initiative and do it this
-;;; way instead.)
-(defun basic-compare (op &key infinite-x-finite-y infinite-y-finite-x)
-  `(((fixnum fixnum) (,op x y))
-
-    ((single-float single-float) (,op x y))
-    #!+long-float
-    (((foreach single-float double-float long-float) long-float)
-     (,op (coerce x 'long-float) y))
-    #!+long-float
-    ((long-float (foreach single-float double-float))
-     (,op x (coerce y 'long-float)))
-    (((foreach single-float double-float) double-float)
-     (,op (coerce x 'double-float) y))
-    ((double-float single-float)
-     (,op x (coerce y 'double-float)))
-    (((foreach single-float double-float #!+long-float long-float) rational)
-     (if (eql y 0)
-        (,op x (coerce 0 '(dispatch-type x)))
-        (if (float-infinity-p x)
-            ,infinite-x-finite-y
-            (,op (rational x) y))))
-    (((foreach bignum fixnum ratio) float)
-     (if (float-infinity-p y)
-        ,infinite-y-finite-x
-        (,op x (rational y))))))
-) ; EVAL-WHEN
-
-(macrolet ((def-two-arg-</> (name op ratio-arg1 ratio-arg2 &rest cases)
-             `(defun ,name (x y)
-               (number-dispatch ((x real) (y real))
-                                (basic-compare
-                                 ,op
-                                 :infinite-x-finite-y
-                                 (,op x (coerce 0 '(dispatch-type x)))
-                                 :infinite-y-finite-x
-                                 (,op (coerce 0 '(dispatch-type y)) y))
-                                (((foreach fixnum bignum) ratio)
-                                 (,op x (,ratio-arg2 (numerator y)
-                                                     (denominator y))))
-                                ((ratio integer)
-                                 (,op (,ratio-arg1 (numerator x)
-                                                   (denominator x))
-                                      y))
-                                ((ratio ratio)
-                                 (,op (* (numerator   (truly-the ratio x))
-                                         (denominator (truly-the ratio y)))
-                                      (* (numerator   (truly-the ratio y))
-                                         (denominator (truly-the ratio x)))))
-                                ,@cases))))
-  (def-two-arg-</> two-arg-< < floor ceiling
-    ((fixnum bignum)
-     (bignum-plus-p y))
-    ((bignum fixnum)
-     (not (bignum-plus-p x)))
-    ((bignum bignum)
-     (minusp (bignum-compare x y))))
-  (def-two-arg-</> two-arg-> > ceiling floor
-    ((fixnum bignum)
-     (not (bignum-plus-p y)))
-    ((bignum fixnum)
-     (bignum-plus-p x))
-    ((bignum bignum)
-     (plusp (bignum-compare x y)))))
-
-(defun two-arg-= (x y)
-  (number-dispatch ((x number) (y number))
-    (basic-compare =
-                  ;; An infinite value is never equal to a finite value.
-                  :infinite-x-finite-y nil
-                  :infinite-y-finite-x nil)
-    ((fixnum (or bignum ratio)) nil)
-
-    ((bignum (or fixnum ratio)) nil)
-    ((bignum bignum)
-     (zerop (bignum-compare x y)))
-
-    ((ratio integer) nil)
-    ((ratio ratio)
-     (and (eql (numerator x) (numerator y))
-         (eql (denominator x) (denominator y))))
-
-    ((complex complex)
-     (and (= (realpart x) (realpart y))
-         (= (imagpart x) (imagpart y))))
-    (((foreach fixnum bignum ratio single-float double-float
-              #!+long-float long-float) complex)
-     (and (= x (realpart y))
-         (zerop (imagpart y))))
-    ((complex (or float rational))
-     (and (= (realpart x) y)
-         (zerop (imagpart x))))))
-
-(defun eql (obj1 obj2)
-  #!+sb-doc
-  "Return T if OBJ1 and OBJ2 represent the same object, otherwise NIL."
-  (or (eq obj1 obj2)
-      (if (or (typep obj2 'fixnum)
-             (not (typep obj2 'number)))
-         nil
-         (macrolet ((foo (&rest stuff)
-                      `(typecase obj2
-                         ,@(mapcar #'(lambda (foo)
-                                       (let ((type (car foo))
-                                             (fn (cadr foo)))
-                                         `(,type
-                                           (and (typep obj1 ',type)
-                                                (,fn obj1 obj2)))))
-                                   stuff))))
-           (foo
-             (single-float eql)
-             (double-float eql)
-             #!+long-float
-             (long-float eql)
-             (bignum
-              (lambda (x y)
-                (zerop (bignum-compare x y))))
-             (ratio
-              (lambda (x y)
-                (and (eql (numerator x) (numerator y))
-                     (eql (denominator x) (denominator y)))))
-             (complex
-              (lambda (x y)
-                (and (eql (realpart x) (realpart y))
-                     (eql (imagpart x) (imagpart y))))))))))
-\f
-;;;; logicals
-
-(defun logior (&rest integers)
-  #!+sb-doc
-  "Returns the bit-wise or of its arguments. Args must be integers."
-  (declare (list integers))
-  (if integers
-      (do ((result (pop integers) (logior result (pop integers))))
-         ((null integers) result))
-      0))
-
-(defun logxor (&rest integers)
-  #!+sb-doc
-  "Returns the bit-wise exclusive or of its arguments. Args must be integers."
-  (declare (list integers))
-  (if integers
-      (do ((result (pop integers) (logxor result (pop integers))))
-         ((null integers) result))
-      0))
-
-(defun logand (&rest integers)
-  #!+sb-doc
-  "Returns the bit-wise and of its arguments. Args must be integers."
-  (declare (list integers))
-  (if integers
-      (do ((result (pop integers) (logand result (pop integers))))
-         ((null integers) result))
-      -1))
-
-(defun logeqv (&rest integers)
-  #!+sb-doc
-  "Returns the bit-wise equivalence of its arguments. Args must be integers."
-  (declare (list integers))
-  (if integers
-      (do ((result (pop integers) (logeqv result (pop integers))))
-         ((null integers) result))
-      -1))
-
-(defun lognand (integer1 integer2)
-  #!+sb-doc
-  "Returns the complement of the logical AND of integer1 and integer2."
-  (lognand integer1 integer2))
-
-(defun lognor (integer1 integer2)
-  #!+sb-doc
-  "Returns the complement of the logical OR of integer1 and integer2."
-  (lognor integer1 integer2))
-
-(defun logandc1 (integer1 integer2)
-  #!+sb-doc
-  "Returns the logical AND of (LOGNOT integer1) and integer2."
-  (logandc1 integer1 integer2))
-
-(defun logandc2 (integer1 integer2)
-  #!+sb-doc
-  "Returns the logical AND of integer1 and (LOGNOT integer2)."
-  (logandc2 integer1 integer2))
-
-(defun logorc1 (integer1 integer2)
-  #!+sb-doc
-  "Returns the logical OR of (LOGNOT integer1) and integer2."
-  (logorc1 integer1 integer2))
-
-(defun logorc2 (integer1 integer2)
-  #!+sb-doc
-  "Returns the logical OR of integer1 and (LOGNOT integer2)."
-  (logorc2 integer1 integer2))
-
-(defun lognot (number)
-  #!+sb-doc
-  "Returns the bit-wise logical not of integer."
-  (etypecase number
-    (fixnum (lognot (truly-the fixnum number)))
-    (bignum (bignum-logical-not number))))
-
-(macrolet ((def-frob (name op big-op)
-            `(defun ,name (x y)
-              (number-dispatch ((x integer) (y integer))
-                (bignum-cross-fixnum ,op ,big-op)))))
-  (def-frob two-arg-and logand bignum-logical-and)
-  (def-frob two-arg-ior logior bignum-logical-ior)
-  (def-frob two-arg-xor logxor bignum-logical-xor))
-
-(defun logcount (integer)
-  #!+sb-doc
-  "Count the number of 1 bits if INTEGER is positive, and the number of 0 bits
-  if INTEGER is negative."
-  (etypecase integer
-    (fixnum
-     (logcount (truly-the (integer 0 #.(max most-positive-fixnum
-                                           (lognot most-negative-fixnum)))
-                         (if (minusp (truly-the fixnum integer))
-                             (lognot (truly-the fixnum integer))
-                             integer))))
-    (bignum
-     (bignum-logcount integer))))
-
-(defun logtest (integer1 integer2)
-  #!+sb-doc
-  "Predicate which returns T if logand of integer1 and integer2 is not zero."
-  (logtest integer1 integer2))
-
-(defun logbitp (index integer)
-  #!+sb-doc
-  "Predicate returns T if bit index of integer is a 1."
-  (logbitp index integer))
-
-(defun ash (integer count)
-  #!+sb-doc
-  "Shifts integer left by count places preserving sign. - count shifts right."
-  (declare (integer integer count))
-  (etypecase integer
-    (fixnum
-     (cond ((zerop integer)
-           0)
-          ((fixnump count)
-           (let ((length (integer-length (truly-the fixnum integer)))
-                 (count (truly-the fixnum count)))
-             (declare (fixnum length count))
-             (cond ((and (plusp count)
-                         (> (+ length count)
-                            (integer-length most-positive-fixnum)))
-                    (bignum-ashift-left (make-small-bignum integer) count))
-                   (t
-                    (truly-the fixnum
-                               (ash (truly-the fixnum integer) count))))))
-          ((minusp count)
-           (if (minusp integer) -1 0))
-          (t
-           (bignum-ashift-left (make-small-bignum integer) count))))
-    (bignum
-     (if (plusp count)
-        (bignum-ashift-left integer count)
-        (bignum-ashift-right integer (- count))))))
-
-(defun integer-length (integer)
-  #!+sb-doc
-  "Returns the number of significant bits in the absolute value of integer."
-  (etypecase integer
-    (fixnum
-     (integer-length (truly-the fixnum integer)))
-    (bignum
-     (bignum-integer-length integer))))
-\f
-;;;; BYTE, bytespecs, and related operations
-
-(defun byte (size position)
-  #!+sb-doc
-  "Returns a byte specifier which may be used by other byte functions."
-  (byte size position))
-
-(defun byte-size (bytespec)
-  #!+sb-doc
-  "Returns the size part of the byte specifier bytespec."
-  (byte-size bytespec))
-
-(defun byte-position (bytespec)
-  #!+sb-doc
-  "Returns the position part of the byte specifier bytespec."
-  (byte-position bytespec))
-
-(defun ldb (bytespec integer)
-  #!+sb-doc
-  "Extract the specified byte from integer, and right justify result."
-  (ldb bytespec integer))
-
-(defun ldb-test (bytespec integer)
-  #!+sb-doc
-  "Returns T if any of the specified bits in integer are 1's."
-  (ldb-test bytespec integer))
-
-(defun mask-field (bytespec integer)
-  #!+sb-doc
-  "Extract the specified byte from integer,  but do not right justify result."
-  (mask-field bytespec integer))
-
-(defun dpb (newbyte bytespec integer)
-  #!+sb-doc
-  "Returns new integer with newbyte in specified position, newbyte is right justified."
-  (dpb newbyte bytespec integer))
-
-(defun deposit-field (newbyte bytespec integer)
-  #!+sb-doc
-  "Returns new integer with newbyte in specified position, newbyte is not right justified."
-  (deposit-field newbyte bytespec integer))
-
-(defun %ldb (size posn integer)
-  (logand (ash integer (- posn))
-         (1- (ash 1 size))))
-
-(defun %mask-field (size posn integer)
-  (logand integer (ash (1- (ash 1 size)) posn)))
-
-(defun %dpb (newbyte size posn integer)
-  (let ((mask (1- (ash 1 size))))
-    (logior (logand integer (lognot (ash mask posn)))
-           (ash (logand newbyte mask) posn))))
-
-(defun %deposit-field (newbyte size posn integer)
-  (let ((mask (ash (ldb (byte size 0) -1) posn)))
-    (logior (logand newbyte mask)
-           (logand integer (lognot mask)))))
-\f
-;;;; BOOLE
-
-;;; The boole function dispaches to any logic operation depending on
-;;;     the value of a variable. Presently, legal selector values are [0..15].
-;;;     boole is open coded for calls with a constant selector. or with calls
-;;;     using any of the constants declared below.
-
-(defconstant boole-clr 0
-  #!+sb-doc
-  "Boole function op, makes BOOLE return 0.")
-
-(defconstant boole-set 1
-  #!+sb-doc
-  "Boole function op, makes BOOLE return -1.")
-
-(defconstant boole-1   2
-  #!+sb-doc
-  "Boole function op, makes BOOLE return integer1.")
-
-(defconstant boole-2   3
-  #!+sb-doc
-  "Boole function op, makes BOOLE return integer2.")
-
-(defconstant boole-c1  4
-  #!+sb-doc
-  "Boole function op, makes BOOLE return complement of integer1.")
-
-(defconstant boole-c2  5
-  #!+sb-doc
-  "Boole function op, makes BOOLE return complement of integer2.")
-
-(defconstant boole-and 6
-  #!+sb-doc
-  "Boole function op, makes BOOLE return logand of integer1 and integer2.")
-
-(defconstant boole-ior 7
-  #!+sb-doc
-  "Boole function op, makes BOOLE return logior of integer1 and integer2.")
-
-(defconstant boole-xor 8
-  #!+sb-doc
-  "Boole function op, makes BOOLE return logxor of integer1 and integer2.")
-
-(defconstant boole-eqv 9
-  #!+sb-doc
-  "Boole function op, makes BOOLE return logeqv of integer1 and integer2.")
-
-(defconstant boole-nand  10
-  #!+sb-doc
-  "Boole function op, makes BOOLE return log nand of integer1 and integer2.")
-
-(defconstant boole-nor   11
-  #!+sb-doc
-  "Boole function op, makes BOOLE return lognor of integer1 and integer2.")
-
-(defconstant boole-andc1 12
-  #!+sb-doc
-  "Boole function op, makes BOOLE return logandc1 of integer1 and integer2.")
-
-(defconstant boole-andc2 13
-  #!+sb-doc
-  "Boole function op, makes BOOLE return logandc2 of integer1 and integer2.")
-
-(defconstant boole-orc1  14
-  #!+sb-doc
-  "Boole function op, makes BOOLE return logorc1 of integer1 and integer2.")
-
-(defconstant boole-orc2  15
-  #!+sb-doc
-  "Boole function op, makes BOOLE return logorc2 of integer1 and integer2.")
-
-(defun boole (op integer1 integer2)
-  #!+sb-doc
-  "Bit-wise boolean function on two integers. Function chosen by OP:
-       0       BOOLE-CLR
-       1       BOOLE-SET
-       2       BOOLE-1
-       3       BOOLE-2
-       4       BOOLE-C1
-       5       BOOLE-C2
-       6       BOOLE-AND
-       7       BOOLE-IOR
-       8       BOOLE-XOR
-       9       BOOLE-EQV
-       10      BOOLE-NAND
-       11      BOOLE-NOR
-       12      BOOLE-ANDC1
-       13      BOOLE-ANDC2
-       14      BOOLE-ORC1
-       15      BOOLE-ORC2"
-  (case op
-    (0 (boole 0 integer1 integer2))
-    (1 (boole 1 integer1 integer2))
-    (2 (boole 2 integer1 integer2))
-    (3 (boole 3 integer1 integer2))
-    (4 (boole 4 integer1 integer2))
-    (5 (boole 5 integer1 integer2))
-    (6 (boole 6 integer1 integer2))
-    (7 (boole 7 integer1 integer2))
-    (8 (boole 8 integer1 integer2))
-    (9 (boole 9 integer1 integer2))
-    (10 (boole 10 integer1 integer2))
-    (11 (boole 11 integer1 integer2))
-    (12 (boole 12 integer1 integer2))
-    (13 (boole 13 integer1 integer2))
-    (14 (boole 14 integer1 integer2))
-    (15 (boole 15 integer1 integer2))
-    (t (error "~S is not of type (mod 16)." op))))
-\f
-;;;; GCD and LCM
-
-(defun gcd (&rest numbers)
-  #!+sb-doc
-  "Returns the greatest common divisor of the arguments, which must be
-  integers. Gcd with no arguments is defined to be 0."
-  (cond ((null numbers) 0)
-       ((null (cdr numbers)) (abs (the integer (car numbers))))
-       (t
-        (do ((gcd (the integer (car numbers))
-                  (gcd gcd (the integer (car rest))))
-             (rest (cdr numbers) (cdr rest)))
-            ((null rest) gcd)
-          (declare (integer gcd)
-                   (list rest))))))
-
-(defun lcm (&rest numbers)
-  #!+sb-doc
-  "Returns the least common multiple of one or more integers. LCM of no
-  arguments is defined to be 1."
-  (cond ((null numbers) 1)
-       ((null (cdr numbers)) (abs (the integer (car numbers))))
-       (t
-        (do ((lcm (the integer (car numbers))
-                  (lcm lcm (the integer (car rest))))
-             (rest (cdr numbers) (cdr rest)))
-            ((null rest) lcm)
-          (declare (integer lcm) (list rest))))))
-
-(defun two-arg-lcm (n m)
-  (declare (integer n m))
-  (* (truncate (max n m) (gcd n m)) (min n m)))
-
-;;; Do the GCD of two integer arguments. With fixnum arguments, we use the
-;;; binary GCD algorithm from Knuth's seminumerical algorithms (slightly
-;;; structurified), otherwise we call BIGNUM-GCD. We pick off the special case
-;;; of 0 before the dispatch so that the bignum code doesn't have to worry
-;;; about "small bignum" zeros.
-(defun two-arg-gcd (u v)
-  (cond ((eql u 0) v)
-       ((eql v 0) u)
-       (t
-        (number-dispatch ((u integer) (v integer))
-          ((fixnum fixnum)
-           (locally
-             (declare (optimize (speed 3) (safety 0)))
-             (do ((k 0 (1+ k))
-                  (u (abs u) (ash u -1))
-                  (v (abs v) (ash v -1)))
-                 ((oddp (logior u v))
-                  (do ((temp (if (oddp u) (- v) (ash u -1))
-                             (ash temp -1)))
-                      (nil)
-                    (declare (fixnum temp))
-                    (when (oddp temp)
-                      (if (plusp temp)
-                          (setq u temp)
-                          (setq v (- temp)))
-                      (setq temp (- u v))
-                      (when (zerop temp)
-                        (let ((res (ash u k)))
-                          (declare (type (signed-byte 31) res)
-                                   (optimize (inhibit-warnings 3)))
-                          (return res))))))
-               (declare (type (mod 30) k)
-                        (type (signed-byte 31) u v)))))
-          ((bignum bignum)
-           (bignum-gcd u v))
-          ((bignum fixnum)
-           (bignum-gcd u (make-small-bignum v)))
-          ((fixnum bignum)
-           (bignum-gcd (make-small-bignum u) v))))))
-\f
-;;; From discussion on comp.lang.lisp and Akira Kurihara.
-(defun isqrt (n)
-  #!+sb-doc
-  "Returns the root of the nearest integer less than n which is a perfect
-   square."
-  (declare (type unsigned-byte n) (values unsigned-byte))
-  ;; Theoretically (> n 7), i.e., n-len-quarter > 0.
-  (if (and (fixnump n) (<= n 24))
-      (cond ((> n 15) 4)
-           ((> n  8) 3)
-           ((> n  3) 2)
-           ((> n  0) 1)
-           (t 0))
-      (let* ((n-len-quarter (ash (integer-length n) -2))
-            (n-half (ash n (- (ash n-len-quarter 1))))
-            (n-half-isqrt (isqrt n-half))
-            (init-value (ash (1+ n-half-isqrt) n-len-quarter)))
-       (loop
-         (let ((iterated-value
-                (ash (+ init-value (truncate n init-value)) -1)))
-           (unless (< iterated-value init-value)
-             (return init-value))
-           (setq init-value iterated-value))))))
-\f
-;;;; miscellaneous number predicates
-
-(macrolet ((def-frob (name doc)
-            `(defun ,name (number) ,doc (,name number))))
-  (def-frob zerop "Returns T if number = 0, NIL otherwise.")
-  (def-frob plusp "Returns T if number > 0, NIL otherwise.")
-  (def-frob minusp "Returns T if number < 0, NIL otherwise.")
-  (def-frob oddp "Returns T if number is odd, NIL otherwise.")
-  (def-frob evenp "Returns T if number is even, NIL otherwise."))
index 05497fc..c594357 100644 (file)
 
 #!-sb-fluid (declaim (freeze-type logical-pathname logical-host))
 \f
-;;; host methods
-
-(def!method print-object ((host host) stream)
-  (print-unreadable-object (host stream :type t :identity t)))
+;;;; UNIX-HOST stuff
+
+(def!struct (unix-host
+            (:make-load-form-fun make-unix-host-load-form)
+            (:include host
+                      (parse #'parse-unix-namestring)
+                      (unparse #'unparse-unix-namestring)
+                      (unparse-host #'unparse-unix-host)
+                      (unparse-directory #'unparse-unix-directory)
+                      (unparse-file #'unparse-unix-file)
+                      (unparse-enough #'unparse-unix-enough)
+                      (customary-case :lower))))
+
+(defvar *unix-host* (make-unix-host))
+
+(defun make-unix-host-load-form (host)
+  (declare (ignore host))
+  '*unix-host*)
+
+;;; Return a value suitable, e.g., for preinitializing
+;;; *DEFAULT-PATHNAME-DEFAULTS* before *DEFAULT-PATHNAME-DEFAULTS* is
+;;; initialized (at which time we can't safely call e.g. #'PATHNAME).
+(defun make-trivial-default-pathname ()
+  (%make-pathname *unix-host* nil nil nil nil :newest))
 \f
 ;;; pathname methods
 
diff --git a/src/compiler/ir1-translators.lisp b/src/compiler/ir1-translators.lisp
new file mode 100644 (file)
index 0000000..82b129f
--- /dev/null
@@ -0,0 +1,1071 @@
+;;;; the usual place for DEF-IR1-TRANSLATOR forms (and their
+;;;; close personal friends)
+
+;;;; 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!C")
+\f
+;;;; control special forms
+
+(def-ir1-translator progn ((&rest forms) start cont)
+  #!+sb-doc
+  "Progn Form*
+  Evaluates each Form in order, returning the values of the last form. With no
+  forms, returns NIL."
+  (ir1-convert-progn-body start cont forms))
+
+(def-ir1-translator if ((test then &optional else) start cont)
+  #!+sb-doc
+  "If Predicate Then [Else]
+  If Predicate evaluates to non-null, evaluate Then and returns its values,
+  otherwise evaluate Else and return its values. Else defaults to NIL."
+  (let* ((pred (make-continuation))
+        (then-cont (make-continuation))
+        (then-block (continuation-starts-block then-cont))
+        (else-cont (make-continuation))
+        (else-block (continuation-starts-block else-cont))
+        (dummy-cont (make-continuation))
+        (node (make-if :test pred
+                       :consequent then-block
+                       :alternative else-block)))
+    (setf (continuation-dest pred) node)
+    (ir1-convert start pred test)
+    (prev-link node pred)
+    (use-continuation node dummy-cont)
+
+    (let ((start-block (continuation-block pred)))
+      (setf (block-last start-block) node)
+      (continuation-starts-block cont)
+
+      (link-blocks start-block then-block)
+      (link-blocks start-block else-block)
+
+      (ir1-convert then-cont cont then)
+      (ir1-convert else-cont cont else))))
+\f
+;;;; BLOCK and TAGBODY
+
+;;;; We make an Entry node to mark the start and a :Entry cleanup to
+;;;; mark its extent. When doing GO or RETURN-FROM, we emit an Exit
+;;;; node.
+
+;;; Make a :ENTRY cleanup and emit an ENTRY node, then convert the
+;;; body in the modified environment. We make CONT start a block now,
+;;; since if it was done later, the block would be in the wrong
+;;; environment.
+(def-ir1-translator block ((name &rest forms) start cont)
+  #!+sb-doc
+  "Block Name Form*
+  Evaluate the Forms as a PROGN. Within the lexical scope of the body,
+  (RETURN-FROM Name Value-Form) can be used to exit the form, returning the
+  result of Value-Form."
+  (unless (symbolp name)
+    (compiler-error "The block name ~S is not a symbol." name))
+  (continuation-starts-block cont)
+  (let* ((dummy (make-continuation))
+        (entry (make-entry))
+        (cleanup (make-cleanup :kind :block
+                               :mess-up entry)))
+    (push entry (lambda-entries (lexenv-lambda *lexenv*)))
+    (setf (entry-cleanup entry) cleanup)
+    (prev-link entry start)
+    (use-continuation entry dummy)
+    
+    (let* ((env-entry (list entry cont))
+           (*lexenv* (make-lexenv :blocks (list (cons name env-entry))
+                                 :cleanup cleanup)))
+      (push env-entry (continuation-lexenv-uses cont))
+      (ir1-convert-progn-body dummy cont forms))))
+
+
+;;; We make CONT start a block just so that it will have a block
+;;; assigned. People assume that when they pass a continuation into
+;;; IR1-CONVERT as CONT, it will have a block when it is done.
+(def-ir1-translator return-from ((name &optional value)
+                                start cont)
+  #!+sb-doc
+  "Return-From Block-Name Value-Form
+  Evaluate the Value-Form, returning its values from the lexically enclosing
+  BLOCK Block-Name. This is constrained to be used only within the dynamic
+  extent of the BLOCK."
+  (continuation-starts-block cont)
+  (let* ((found (or (lexenv-find name blocks)
+                   (compiler-error "return for unknown block: ~S" name)))
+        (value-cont (make-continuation))
+        (entry (first found))
+        (exit (make-exit :entry entry
+                         :value value-cont)))
+    (push exit (entry-exits entry))
+    (setf (continuation-dest value-cont) exit)
+    (ir1-convert start value-cont value)
+    (prev-link exit value-cont)
+    (use-continuation exit (second found))))
+
+;;; Return a list of the segments of a TAGBODY. Each segment looks
+;;; like (<tag> <form>* (go <next tag>)). That is, we break up the
+;;; tagbody into segments of non-tag statements, and explicitly
+;;; represent the drop-through with a GO. The first segment has a
+;;; dummy NIL tag, since it represents code before the first tag. The
+;;; last segment (which may also be the first segment) ends in NIL
+;;; rather than a GO.
+(defun parse-tagbody (body)
+  (declare (list body))
+  (collect ((segments))
+    (let ((current (cons nil body)))
+      (loop
+       (let ((tag-pos (position-if (complement #'listp) current :start 1)))
+         (unless tag-pos
+           (segments `(,@current nil))
+           (return))
+         (let ((tag (elt current tag-pos)))
+           (when (assoc tag (segments))
+             (compiler-error
+              "The tag ~S appears more than once in the tagbody."
+              tag))
+           (unless (or (symbolp tag) (integerp tag))
+             (compiler-error "~S is not a legal tagbody statement." tag))
+           (segments `(,@(subseq current 0 tag-pos) (go ,tag))))
+         (setq current (nthcdr tag-pos current)))))
+    (segments)))
+
+;;; Set up the cleanup, emitting the entry node. Then make a block for
+;;; each tag, building up the tag list for LEXENV-TAGS as we go.
+;;; Finally, convert each segment with the precomputed Start and Cont
+;;; values.
+(def-ir1-translator tagbody ((&rest statements) start cont)
+  #!+sb-doc
+  "Tagbody {Tag | Statement}*
+  Define tags for used with GO. The Statements are evaluated in order
+  (skipping Tags) and NIL is returned. If a statement contains a GO to a
+  defined Tag within the lexical scope of the form, then control is transferred
+  to the next statement following that tag. A Tag must an integer or a
+  symbol. A statement must be a list. Other objects are illegal within the
+  body."
+  (continuation-starts-block cont)
+  (let* ((dummy (make-continuation))
+        (entry (make-entry))
+        (segments (parse-tagbody statements))
+        (cleanup (make-cleanup :kind :tagbody
+                               :mess-up entry)))
+    (push entry (lambda-entries (lexenv-lambda *lexenv*)))
+    (setf (entry-cleanup entry) cleanup)
+    (prev-link entry start)
+    (use-continuation entry dummy)
+
+    (collect ((tags)
+             (starts)
+             (conts))
+      (starts dummy)
+      (dolist (segment (rest segments))
+       (let* ((tag-cont (make-continuation))
+               (tag (list (car segment) entry tag-cont)))          
+         (conts tag-cont)
+         (starts tag-cont)
+         (continuation-starts-block tag-cont)
+          (tags tag)
+          (push (cdr tag) (continuation-lexenv-uses tag-cont))))
+      (conts cont)
+
+      (let ((*lexenv* (make-lexenv :cleanup cleanup :tags (tags))))
+       (mapc (lambda (segment start cont)
+               (ir1-convert-progn-body start cont (rest segment)))
+             segments (starts) (conts))))))
+
+;;; Emit an EXIT node without any value.
+(def-ir1-translator go ((tag) start cont)
+  #!+sb-doc
+  "Go Tag
+  Transfer control to the named Tag in the lexically enclosing TAGBODY. This
+  is constrained to be used only within the dynamic extent of the TAGBODY."
+  (continuation-starts-block cont)
+  (let* ((found (or (lexenv-find tag tags :test #'eql)
+                   (compiler-error "Go to nonexistent tag: ~S." tag)))
+        (entry (first found))
+        (exit (make-exit :entry entry)))
+    (push exit (entry-exits entry))
+    (prev-link exit start)
+    (use-continuation exit (second found))))
+\f
+;;;; translators for compiler-magic special forms
+
+;;; This handles EVAL-WHEN in non-top-level forms. (EVAL-WHENs in
+;;; top-level forms are picked off and handled by PROCESS-TOP-LEVEL-FORM,
+;;; so that they're never seen at this level.)
+;;;
+;;; ANSI "3.2.3.1 Processing of Top Level Forms" says that processing
+;;; of non-top-level EVAL-WHENs is very simple:
+;;;   EVAL-WHEN forms cause compile-time evaluation only at top level.
+;;;   Both :COMPILE-TOPLEVEL and :LOAD-TOPLEVEL situation specifications
+;;;   are ignored for non-top-level forms. For non-top-level forms, an
+;;;   eval-when specifying the :EXECUTE situation is treated as an
+;;;   implicit PROGN including the forms in the body of the EVAL-WHEN
+;;;   form; otherwise, the forms in the body are ignored. 
+(def-ir1-translator eval-when ((situations &rest forms) start cont)
+  #!+sb-doc
+  "EVAL-WHEN (Situation*) Form*
+  Evaluate the Forms in the specified Situations (any of :COMPILE-TOPLEVEL,
+  :LOAD-TOPLEVEL, or :EXECUTE, or (deprecated) COMPILE, LOAD, or EVAL)."
+  (multiple-value-bind (ct lt e) (parse-eval-when-situations situations)
+    (declare (ignore ct lt))
+    (ir1-convert-progn-body start cont (and e forms)))
+  (values))
+
+;;; common logic for MACROLET and SYMBOL-MACROLET
+;;;
+;;; Call DEFINITIONIZE-FUN on each element of DEFINITIONS to find its
+;;; in-lexenv representation, stuff the results into *LEXENV*, and
+;;; call FUN (with no arguments).
+(defun %funcall-in-foomacrolet-lexenv (definitionize-fun
+                                      definitionize-keyword
+                                      definitions
+                                      fun)
+  (declare (type function definitionize-fun fun))
+  (declare (type (member :variables :functions) definitionize-keyword))
+  (declare (type list definitions))
+  (unless (= (length definitions)
+             (length (remove-duplicates definitions :key #'first)))
+    (compiler-style-warning "duplicate definitions in ~S" definitions))
+  (let* ((processed-definitions (mapcar definitionize-fun definitions))
+         (*lexenv* (make-lexenv definitionize-keyword processed-definitions)))
+    (funcall fun)))
+
+;;; Tweak *LEXENV* to include the DEFINITIONS from a MACROLET, then
+;;; call FUN (with no arguments).
+;;;
+;;; This is split off from the IR1 convert method so that it can be
+;;; shared by the special-case top-level MACROLET processing code.
+(defun funcall-in-macrolet-lexenv (definitions fun)
+  (%funcall-in-foomacrolet-lexenv
+   (lambda (definition)
+     (unless (list-of-length-at-least-p definition 2)
+       (compiler-error
+       "The list ~S is too short to be a legal local macro definition."
+       definition))
+     (destructuring-bind (name arglist &body body) definition
+       (unless (symbolp name)
+        (compiler-error "The local macro name ~S is not a symbol." name))
+       (let ((whole (gensym "WHOLE"))
+            (environment (gensym "ENVIRONMENT")))
+        (multiple-value-bind (body local-decls)
+            (parse-defmacro arglist whole body name 'macrolet
+                            :environment environment)
+          `(,name macro .
+                  ,(compile nil
+                            `(lambda (,whole ,environment)
+                               ,@local-decls
+                               (block ,name ,body))))))))
+   :functions
+   definitions
+   fun))
+
+(def-ir1-translator macrolet ((definitions &rest body) start cont)
+  #!+sb-doc
+  "MACROLET ({(Name Lambda-List Form*)}*) Body-Form*
+  Evaluate the Body-Forms in an environment with the specified local macros
+  defined. Name is the local macro name, Lambda-List is the DEFMACRO style
+  destructuring lambda list, and the Forms evaluate to the expansion. The
+  Forms are evaluated in the null environment."
+  (funcall-in-macrolet-lexenv definitions
+                             (lambda ()
+                               (ir1-translate-locally body start cont))))
+
+(defun funcall-in-symbol-macrolet-lexenv (definitions fun)
+  (%funcall-in-foomacrolet-lexenv
+   (lambda (definition)
+     (unless (proper-list-of-length-p definition 2)
+       (compiler-error "malformed symbol/expansion pair: ~S" definition))
+     (destructuring-bind (name expansion) definition
+       (unless (symbolp name)
+         (compiler-error
+          "The local symbol macro name ~S is not a symbol."
+          name))
+       `(,name . (MACRO . ,expansion))))
+   :variables
+   definitions
+   fun))
+  
+(def-ir1-translator symbol-macrolet ((macrobindings &body body) start cont)
+  #!+sb-doc
+  "SYMBOL-MACROLET ({(Name Expansion)}*) Decl* Form*
+  Define the Names as symbol macros with the given Expansions. Within the
+  body, references to a Name will effectively be replaced with the Expansion."
+  (funcall-in-symbol-macrolet-lexenv
+   macrobindings
+   (lambda ()
+     (ir1-translate-locally body start cont))))
+
+;;; not really a special form, but..
+(def-ir1-translator declare ((&rest stuff) start cont)
+  (declare (ignore stuff))
+  ;; We ignore START and CONT too, but we can't use DECLARE IGNORE to
+  ;; tell the compiler about it here, because the DEF-IR1-TRANSLATOR
+  ;; macro would put the DECLARE in the wrong place, so..
+  start cont
+  (compiler-error "misplaced declaration"))
+\f
+;;;; %PRIMITIVE
+;;;;
+;;;; Uses of %PRIMITIVE are either expanded into Lisp code or turned
+;;;; into a funny function.
+
+;;; Carefully evaluate a list of forms, returning a list of the results.
+(defun eval-info-args (args)
+  (declare (list args))
+  (handler-case (mapcar #'eval args)
+    (error (condition)
+      (compiler-error "Lisp error during evaluation of info args:~%~A"
+                     condition))))
+
+;;; If there is a primitive translator, then we expand the call.
+;;; Otherwise, we convert to the %%PRIMITIVE funny function. The first
+;;; argument is the template, the second is a list of the results of
+;;; any codegen-info args, and the remaining arguments are the runtime
+;;; arguments.
+;;;
+;;; We do a bunch of error checking now so that we don't bomb out with
+;;; a fatal error during IR2 conversion.
+;;;
+;;; KLUDGE: It's confusing having multiple names floating around for
+;;; nearly the same concept: PRIMITIVE, TEMPLATE, VOP. Now that CMU
+;;; CL's *PRIMITIVE-TRANSLATORS* stuff is gone, we could call
+;;; primitives VOPs, rename TEMPLATE to VOP-TEMPLATE, rename
+;;; BACKEND-TEMPLATE-NAMES to BACKEND-VOPS, and rename %PRIMITIVE to
+;;; VOP or %VOP.. -- WHN 2001-06-11
+;;; FIXME: Look at doing this ^, it doesn't look too hard actually.
+(def-ir1-translator %primitive ((name &rest args) start cont)
+  (unless (symbolp name)
+    (compiler-error "The primitive name ~S is not a symbol." name))
+
+  (let* ((template (or (gethash name *backend-template-names*)
+                      (compiler-error
+                       "The primitive name ~A is not defined."
+                       name)))
+        (required (length (template-arg-types template)))
+        (info (template-info-arg-count template))
+        (min (+ required info))
+        (nargs (length args)))
+    (if (template-more-args-type template)
+       (when (< nargs min)
+         (compiler-error "Primitive ~A was called with ~R argument~:P, ~
+                          but wants at least ~R."
+                         name
+                         nargs
+                         min))
+       (unless (= nargs min)
+         (compiler-error "Primitive ~A was called with ~R argument~:P, ~
+                          but wants exactly ~R."
+                         name
+                         nargs
+                         min)))
+
+    (when (eq (template-result-types template) :conditional)
+      (compiler-error
+       "%PRIMITIVE was used with a conditional template."))
+
+    (when (template-more-results-type template)
+      (compiler-error
+       "%PRIMITIVE was used with an unknown values template."))
+
+    (ir1-convert start
+                cont
+                `(%%primitive ',template
+                              ',(eval-info-args
+                                 (subseq args required min))
+                              ,@(subseq args 0 required)
+                              ,@(subseq args min)))))
+\f
+;;;; QUOTE and FUNCTION
+
+(def-ir1-translator quote ((thing) start cont)
+  #!+sb-doc
+  "QUOTE Value
+  Return Value without evaluating it."
+  (reference-constant start cont thing))
+
+(def-ir1-translator function ((thing) start cont)
+  #!+sb-doc
+  "FUNCTION Name
+  Return the lexically apparent definition of the function Name. Name may also
+  be a lambda."
+  (if (consp thing)
+      (case (car thing)
+       ((lambda)
+        (reference-leaf start cont (ir1-convert-lambda thing)))
+       ((setf)
+        (let ((var (find-lexically-apparent-function
+                    thing "as the argument to FUNCTION")))
+          (reference-leaf start cont var)))
+       ((instance-lambda)
+        (let ((res (ir1-convert-lambda `(lambda ,@(cdr thing)))))
+          (setf (getf (functional-plist res) :fin-function) t)
+          (reference-leaf start cont res)))
+       (t
+        (compiler-error "~S is not a legal function name." thing)))
+      (let ((var (find-lexically-apparent-function
+                 thing "as the argument to FUNCTION")))
+       (reference-leaf start cont var))))
+\f
+;;;; FUNCALL
+
+;;; FUNCALL is implemented on %FUNCALL, which can only call functions
+;;; (not symbols). %FUNCALL is used directly in some places where the
+;;; call should always be open-coded even if FUNCALL is :NOTINLINE.
+(deftransform funcall ((function &rest args) * * :when :both)
+  (let ((arg-names (make-gensym-list (length args))))
+    `(lambda (function ,@arg-names)
+       (%funcall ,(if (csubtypep (continuation-type function)
+                                (specifier-type 'function))
+                     'function
+                     '(%coerce-callable-to-function function))
+                ,@arg-names))))
+
+(def-ir1-translator %funcall ((function &rest args) start cont)
+  (let ((fun-cont (make-continuation)))
+    (ir1-convert start fun-cont function)
+    (assert-continuation-type fun-cont (specifier-type 'function))
+    (ir1-convert-combination-args fun-cont cont args)))
+
+;;; This source transform exists to reduce the amount of work for the
+;;; compiler. If the called function is a FUNCTION form, then convert
+;;; directly to %FUNCALL, instead of waiting around for type
+;;; inference.
+(def-source-transform funcall (function &rest args)
+  (if (and (consp function) (eq (car function) 'function))
+      `(%funcall ,function ,@args)
+      (values nil t)))
+
+(deftransform %coerce-callable-to-function ((thing) (function) *
+                                           :when :both
+                                           :important t)
+  "optimize away possible call to FDEFINITION at runtime"
+  'thing)
+\f
+;;;; LET and LET*
+;;;;
+;;;; (LET and LET* can't be implemented as macros due to the fact that
+;;;; any pervasive declarations also affect the evaluation of the
+;;;; arguments.)
+
+;;; Given a list of binding specifiers in the style of Let, return:
+;;;  1. The list of var structures for the variables bound.
+;;;  2. The initial value form for each variable.
+;;;
+;;; The variable names are checked for legality and globally special
+;;; variables are marked as such. Context is the name of the form, for
+;;; error reporting purposes.
+(declaim (ftype (function (list symbol) (values list list list))
+               extract-let-variables))
+(defun extract-let-variables (bindings context)
+  (collect ((vars)
+           (vals)
+           (names))
+    (flet ((get-var (name)
+            (varify-lambda-arg name
+                               (if (eq context 'let*)
+                                   nil
+                                   (names)))))
+      (dolist (spec bindings)
+       (cond ((atom spec)
+              (let ((var (get-var spec)))
+                (vars var)
+                (names (cons spec var))
+                (vals nil)))
+             (t
+              (unless (proper-list-of-length-p spec 1 2)
+                (compiler-error "The ~S binding spec ~S is malformed."
+                                context
+                                spec))
+              (let* ((name (first spec))
+                     (var (get-var name)))
+                (vars var)
+                (names name)
+                (vals (second spec)))))))
+
+    (values (vars) (vals) (names))))
+
+(def-ir1-translator let ((bindings &body body)
+                        start cont)
+  #!+sb-doc
+  "LET ({(Var [Value]) | Var}*) Declaration* Form*
+  During evaluation of the Forms, bind the Vars to the result of evaluating the
+  Value forms. The variables are bound in parallel after all of the Values are
+  evaluated."
+  (multiple-value-bind (forms decls) (sb!sys:parse-body body nil)
+    (multiple-value-bind (vars values) (extract-let-variables bindings 'let)
+      (let* ((*lexenv* (process-decls decls vars nil cont))
+            (fun-cont (make-continuation))
+            (fun (ir1-convert-lambda-body forms vars)))
+       (reference-leaf start fun-cont fun)
+       (ir1-convert-combination-args fun-cont cont values)))))
+
+(def-ir1-translator let* ((bindings &body body)
+                         start cont)
+  #!+sb-doc
+  "LET* ({(Var [Value]) | Var}*) Declaration* Form*
+  Similar to LET, but the variables are bound sequentially, allowing each Value
+  form to reference any of the previous Vars."
+  (multiple-value-bind (forms decls) (sb!sys:parse-body body nil)
+    (multiple-value-bind (vars values) (extract-let-variables bindings 'let*)
+      (let ((*lexenv* (process-decls decls vars nil cont)))
+       (ir1-convert-aux-bindings start cont forms vars values)))))
+
+;;; logic shared between IR1 translators for LOCALLY, MACROLET,
+;;; and SYMBOL-MACROLET
+;;;
+;;; Note that all these things need to preserve top-level-formness,
+;;; but we don't need to worry about that within an IR1 translator,
+;;; since top-level-formness is picked off by PROCESS-TOP-LEVEL-FOO
+;;; forms before we hit the IR1 transform level.
+(defun ir1-translate-locally (body start cont)
+  (declare (type list body) (type continuation start cont))
+  (multiple-value-bind (forms decls) (sb!sys:parse-body body nil)
+    (let ((*lexenv* (process-decls decls nil nil cont)))
+      (ir1-convert-aux-bindings start cont forms nil nil))))
+
+(def-ir1-translator locally ((&body body) start cont)
+  #!+sb-doc
+  "LOCALLY Declaration* Form*
+  Sequentially evaluate the Forms in a lexical environment where the
+  the Declarations have effect. If LOCALLY is a top-level form, then
+  the Forms are also processed as top-level forms."
+  (ir1-translate-locally body start cont))
+\f
+;;;; FLET and LABELS
+
+;;; Given a list of local function specifications in the style of
+;;; FLET, return lists of the function names and of the lambdas which
+;;; are their definitions.
+;;;
+;;; The function names are checked for legality. CONTEXT is the name
+;;; of the form, for error reporting.
+(declaim (ftype (function (list symbol) (values list list))
+               extract-flet-variables))
+(defun extract-flet-variables (definitions context)
+  (collect ((names)
+           (defs))
+    (dolist (def definitions)
+      (when (or (atom def) (< (length def) 2))
+       (compiler-error "The ~S definition spec ~S is malformed." context def))
+
+      (let ((name (check-function-name (first def))))
+       (names name)
+       (multiple-value-bind (forms decls) (sb!sys:parse-body (cddr def))
+         (defs `(lambda ,(second def)
+                  ,@decls
+                  (block ,(function-name-block-name name)
+                    . ,forms))))))
+    (values (names) (defs))))
+
+(def-ir1-translator flet ((definitions &body body)
+                         start cont)
+  #!+sb-doc
+  "FLET ({(Name Lambda-List Declaration* Form*)}*) Declaration* Body-Form*
+  Evaluate the Body-Forms with some local function definitions. The bindings
+  do not enclose the definitions; any use of Name in the Forms will refer to
+  the lexically apparent function definition in the enclosing environment."
+  (multiple-value-bind (forms decls) (sb!sys:parse-body body nil)
+    (multiple-value-bind (names defs)
+       (extract-flet-variables definitions 'flet)
+      (let* ((fvars (mapcar (lambda (n d)
+                             (ir1-convert-lambda d n))
+                           names defs))
+            (*lexenv* (make-lexenv
+                       :default (process-decls decls nil fvars cont)
+                       :functions (pairlis names fvars))))
+       (ir1-convert-progn-body start cont forms)))))
+
+;;; For LABELS, we have to create dummy function vars and add them to
+;;; the function namespace while converting the functions. We then
+;;; modify all the references to these leaves so that they point to
+;;; the real functional leaves. We also backpatch the FENV so that if
+;;; the lexical environment is used for inline expansion we will get
+;;; the right functions.
+(def-ir1-translator labels ((definitions &body body) start cont)
+  #!+sb-doc
+  "LABELS ({(Name Lambda-List Declaration* Form*)}*) Declaration* Body-Form*
+  Evaluate the Body-Forms with some local function definitions. The bindings
+  enclose the new definitions, so the defined functions can call themselves or
+  each other."
+  (multiple-value-bind (forms decls) (sb!sys:parse-body body nil)
+    (multiple-value-bind (names defs)
+       (extract-flet-variables definitions 'labels)
+      (let* ((new-fenv (loop for name in names
+                            collect (cons name (make-functional :name name))))
+            (real-funs
+             (let ((*lexenv* (make-lexenv :functions new-fenv)))
+               (mapcar (lambda (n d)
+                         (ir1-convert-lambda d n))
+                       names defs))))
+
+       (loop for real in real-funs and env in new-fenv do
+             (let ((dum (cdr env)))
+               (substitute-leaf real dum)
+               (setf (cdr env) real)))
+
+       (let ((*lexenv* (make-lexenv
+                        :default (process-decls decls nil real-funs cont)
+                        :functions (pairlis names real-funs))))
+         (ir1-convert-progn-body start cont forms))))))
+\f
+;;;; THE
+
+;;; Do stuff to recognize a THE or VALUES declaration. CONT is the
+;;; continuation that the assertion applies to, TYPE is the type
+;;; specifier and Lexenv is the current lexical environment. NAME is
+;;; the name of the declaration we are doing, for use in error
+;;; messages.
+;;;
+;;; This is somewhat involved, since a type assertion may only be made
+;;; on a continuation, not on a node. We can't just set the
+;;; continuation asserted type and let it go at that, since there may
+;;; be parallel THE's for the same continuation, i.e.:
+;;;     (if ...
+;;;     (the foo ...)
+;;;     (the bar ...))
+;;;
+;;; In this case, our representation can do no better than the union
+;;; of these assertions. And if there is a branch with no assertion,
+;;; we have nothing at all. We really need to recognize scoping, since
+;;; we need to be able to discern between parallel assertions (which
+;;; we union) and nested ones (which we intersect).
+;;;
+;;; We represent the scoping by throwing our innermost (intersected)
+;;; assertion on CONT into the TYPE-RESTRICTIONS. As we go down, we
+;;; intersect our assertions together. If CONT has no uses yet, we
+;;; have not yet bottomed out on the first COND branch; in this case
+;;; we optimistically assume that this type will be the one we end up
+;;; with, and set the ASSERTED-TYPE to it. We can never get better
+;;; than the type that we have the first time we bottom out. Later
+;;; THE's (or the absence thereof) can only weaken this result.
+;;;
+;;; We make this work by getting USE-CONTINUATION to do the unioning
+;;; across COND branches. We can't do it here, since we don't know how
+;;; many branches there are going to be.
+(defun do-the-stuff (type cont lexenv name)
+  (declare (type continuation cont) (type lexenv lexenv))
+  (let* ((ctype (values-specifier-type type))
+        (old-type (or (lexenv-find cont type-restrictions)
+                      *wild-type*))
+        (intersects (values-types-equal-or-intersect old-type ctype))
+        (int (values-type-intersection old-type ctype))
+        (new (if intersects int old-type)))
+    (when (null (find-uses cont))
+      (setf (continuation-asserted-type cont) new))
+    (when (and (not intersects)
+              (not (policy *lexenv*
+                           (= inhibit-warnings 3)))) ;FIXME: really OK to suppress?
+      (compiler-warning
+       "The type ~S in ~S declaration conflicts with an enclosing assertion:~%   ~S"
+       (type-specifier ctype)
+       name
+       (type-specifier old-type)))
+    (make-lexenv :type-restrictions `((,cont . ,new))
+                :default lexenv)))
+
+;;; Assert that FORM evaluates to the specified type (which may be a
+;;; VALUES type).
+;;;
+;;; FIXME: In a version of CMU CL that I used at Cadabra ca. 20000101,
+;;; this didn't seem to expand into an assertion, at least for ALIEN
+;;; values. Check that SBCL doesn't have this problem.
+(def-ir1-translator the ((type value) start cont)
+  (let ((*lexenv* (do-the-stuff type cont *lexenv* 'the)))
+    (ir1-convert start cont value)))
+
+;;; This is like the THE special form, except that it believes
+;;; whatever you tell it. It will never generate a type check, but
+;;; will cause a warning if the compiler can prove the assertion is
+;;; wrong.
+;;;
+;;; Since the CONTINUATION-DERIVED-TYPE is computed as the union of
+;;; its uses's types, setting it won't work. Instead we must intersect
+;;; the type with the uses's DERIVED-TYPE.
+(def-ir1-translator truly-the ((type value) start cont)
+  #!+sb-doc
+  (declare (inline member))
+  (let ((type (values-specifier-type type))
+       (old (find-uses cont)))
+    (ir1-convert start cont value)
+    (do-uses (use cont)
+      (unless (member use old :test #'eq)
+       (derive-node-type use type)))))
+\f
+;;;; SETQ
+
+;;; If there is a definition in LEXENV-VARIABLES, just set that,
+;;; otherwise look at the global information. If the name is for a
+;;; constant, then error out.
+(def-ir1-translator setq ((&whole source &rest things) start cont)
+  (let ((len (length things)))
+    (when (oddp len)
+      (compiler-error "odd number of args to SETQ: ~S" source))
+    (if (= len 2)
+       (let* ((name (first things))
+              (leaf (or (lexenv-find name variables)
+                        (find-free-variable name))))
+         (etypecase leaf
+           (leaf
+            (when (or (constant-p leaf)
+                      (and (global-var-p leaf)
+                           (eq (global-var-kind leaf) :constant)))
+              (compiler-error "~S is a constant and thus can't be set." name))
+            (when (and (lambda-var-p leaf)
+                       (lambda-var-ignorep leaf))
+              ;; ANSI's definition of "Declaration IGNORE, IGNORABLE"
+              ;; requires that this be a STYLE-WARNING, not a full warning.
+              (compiler-style-warning
+               "~S is being set even though it was declared to be ignored."
+               name))
+            (set-variable start cont leaf (second things)))
+           (cons
+            (aver (eq (car leaf) 'MACRO))
+            (ir1-convert start cont `(setf ,(cdr leaf) ,(second things))))
+           (heap-alien-info
+            (ir1-convert start cont
+                         `(%set-heap-alien ',leaf ,(second things))))))
+       (collect ((sets))
+         (do ((thing things (cddr thing)))
+             ((endp thing)
+              (ir1-convert-progn-body start cont (sets)))
+           (sets `(setq ,(first thing) ,(second thing))))))))
+
+;;; This is kind of like REFERENCE-LEAF, but we generate a SET node.
+;;; This should only need to be called in SETQ.
+(defun set-variable (start cont var value)
+  (declare (type continuation start cont) (type basic-var var))
+  (let ((dest (make-continuation)))
+    (setf (continuation-asserted-type dest) (leaf-type var))
+    (ir1-convert start dest value)
+    (let ((res (make-set :var var :value dest)))
+      (setf (continuation-dest dest) res)
+      (setf (leaf-ever-used var) t)
+      (push res (basic-var-sets var))
+      (prev-link res dest)
+      (use-continuation res cont))))
+\f
+;;;; CATCH, THROW and UNWIND-PROTECT
+
+;;; We turn THROW into a multiple-value-call of a magical function,
+;;; since as as far as IR1 is concerned, it has no interesting
+;;; properties other than receiving multiple-values.
+(def-ir1-translator throw ((tag result) start cont)
+  #!+sb-doc
+  "Throw Tag Form
+  Do a non-local exit, return the values of Form from the CATCH whose tag
+  evaluates to the same thing as Tag."
+  (ir1-convert start cont
+              `(multiple-value-call #'%throw ,tag ,result)))
+
+;;; This is a special special form used to instantiate a cleanup as
+;;; the current cleanup within the body. KIND is a the kind of cleanup
+;;; to make, and MESS-UP is a form that does the mess-up action. We
+;;; make the MESS-UP be the USE of the MESS-UP form's continuation,
+;;; and introduce the cleanup into the lexical environment. We
+;;; back-patch the ENTRY-CLEANUP for the current cleanup to be the new
+;;; cleanup, since this inner cleanup is the interesting one.
+(def-ir1-translator %within-cleanup ((kind mess-up &body body) start cont)
+  (let ((dummy (make-continuation))
+       (dummy2 (make-continuation)))
+    (ir1-convert start dummy mess-up)
+    (let* ((mess-node (continuation-use dummy))
+          (cleanup (make-cleanup :kind kind
+                                 :mess-up mess-node))
+          (old-cup (lexenv-cleanup *lexenv*))
+          (*lexenv* (make-lexenv :cleanup cleanup)))
+      (setf (entry-cleanup (cleanup-mess-up old-cup)) cleanup)
+      (ir1-convert dummy dummy2 '(%cleanup-point))
+      (ir1-convert-progn-body dummy2 cont body))))
+
+;;; This is a special special form that makes an "escape function"
+;;; which returns unknown values from named block. We convert the
+;;; function, set its kind to :ESCAPE, and then reference it. The
+;;; :Escape kind indicates that this function's purpose is to
+;;; represent a non-local control transfer, and that it might not
+;;; actually have to be compiled.
+;;;
+;;; Note that environment analysis replaces references to escape
+;;; functions with references to the corresponding NLX-INFO structure.
+(def-ir1-translator %escape-function ((tag) start cont)
+  (let ((fun (ir1-convert-lambda
+             `(lambda ()
+                (return-from ,tag (%unknown-values))))))
+    (setf (functional-kind fun) :escape)
+    (reference-leaf start cont fun)))
+
+;;; Yet another special special form. This one looks up a local
+;;; function and smashes it to a :CLEANUP function, as well as
+;;; referencing it.
+(def-ir1-translator %cleanup-function ((name) start cont)
+  (let ((fun (lexenv-find name functions)))
+    (aver (lambda-p fun))
+    (setf (functional-kind fun) :cleanup)
+    (reference-leaf start cont fun)))
+
+;;; We represent the possibility of the control transfer by making an
+;;; "escape function" that does a lexical exit, and instantiate the
+;;; cleanup using %WITHIN-CLEANUP.
+(def-ir1-translator catch ((tag &body body) start cont)
+  #!+sb-doc
+  "Catch Tag Form*
+  Evaluates Tag and instantiates it as a catcher while the body forms are
+  evaluated in an implicit PROGN. If a THROW is done to Tag within the dynamic
+  scope of the body, then control will be transferred to the end of the body
+  and the thrown values will be returned."
+  (ir1-convert
+   start cont
+   (let ((exit-block (gensym "EXIT-BLOCK-")))
+     `(block ,exit-block
+       (%within-cleanup
+           :catch
+           (%catch (%escape-function ,exit-block) ,tag)
+         ,@body)))))
+
+;;; UNWIND-PROTECT is similar to CATCH, but more hairy. We make the
+;;; cleanup forms into a local function so that they can be referenced
+;;; both in the case where we are unwound and in any local exits. We
+;;; use %CLEANUP-FUNCTION on this to indicate that reference by
+;;; %UNWIND-PROTECT ISN'T "real", and thus doesn't cause creation of
+;;; an XEP.
+(def-ir1-translator unwind-protect ((protected &body cleanup) start cont)
+  #!+sb-doc
+  "Unwind-Protect Protected Cleanup*
+  Evaluate the form Protected, returning its values. The cleanup forms are
+  evaluated whenever the dynamic scope of the Protected form is exited (either
+  due to normal completion or a non-local exit such as THROW)."
+  (ir1-convert
+   start cont
+   (let ((cleanup-fun (gensym "CLEANUP-FUN-"))
+        (drop-thru-tag (gensym "DROP-THRU-TAG-"))
+        (exit-tag (gensym "EXIT-TAG-"))
+        (next (gensym "NEXT"))
+        (start (gensym "START"))
+        (count (gensym "COUNT")))
+     `(flet ((,cleanup-fun () ,@cleanup nil))
+       ;; FIXME: If we ever get DYNAMIC-EXTENT working, then
+       ;; ,CLEANUP-FUN should probably be declared DYNAMIC-EXTENT,
+       ;; and something can be done to make %ESCAPE-FUNCTION have
+       ;; dynamic extent too.
+       (block ,drop-thru-tag
+         (multiple-value-bind (,next ,start ,count)
+             (block ,exit-tag
+               (%within-cleanup
+                   :unwind-protect
+                   (%unwind-protect (%escape-function ,exit-tag)
+                                    (%cleanup-function ,cleanup-fun))
+                 (return-from ,drop-thru-tag ,protected)))
+           (,cleanup-fun)
+           (%continue-unwind ,next ,start ,count)))))))
+\f
+;;;; multiple-value stuff
+
+;;; If there are arguments, MULTIPLE-VALUE-CALL turns into an
+;;; MV-COMBINATION.
+;;;
+;;; If there are no arguments, then we convert to a normal
+;;; combination, ensuring that a MV-COMBINATION always has at least
+;;; one argument. This can be regarded as an optimization, but it is
+;;; more important for simplifying compilation of MV-COMBINATIONS.
+(def-ir1-translator multiple-value-call ((fun &rest args) start cont)
+  #!+sb-doc
+  "MULTIPLE-VALUE-CALL Function Values-Form*
+  Call Function, passing all the values of each Values-Form as arguments,
+  values from the first Values-Form making up the first argument, etc."
+  (let* ((fun-cont (make-continuation))
+        (node (if args
+                  (make-mv-combination fun-cont)
+                  (make-combination fun-cont))))
+    (ir1-convert start fun-cont
+                (if (and (consp fun) (eq (car fun) 'function))
+                    fun
+                    `(%coerce-callable-to-function ,fun)))
+    (setf (continuation-dest fun-cont) node)
+    (assert-continuation-type fun-cont
+                             (specifier-type '(or function symbol)))
+    (collect ((arg-conts))
+      (let ((this-start fun-cont))
+       (dolist (arg args)
+         (let ((this-cont (make-continuation node)))
+           (ir1-convert this-start this-cont arg)
+           (setq this-start this-cont)
+           (arg-conts this-cont)))
+       (prev-link node this-start)
+       (use-continuation node cont)
+       (setf (basic-combination-args node) (arg-conts))))))
+
+;;; MULTIPLE-VALUE-PROG1 is represented implicitly in IR1 by having a
+;;; the result code use result continuation (CONT), but transfer
+;;; control to the evaluation of the body. In other words, the result
+;;; continuation isn't IMMEDIATELY-USED-P by the nodes that compute
+;;; the result.
+;;;
+;;; In order to get the control flow right, we convert the result with
+;;; a dummy result continuation, then convert all the uses of the
+;;; dummy to be uses of CONT. If a use is an EXIT, then we also
+;;; substitute CONT for the dummy in the corresponding ENTRY node so
+;;; that they are consistent. Note that this doesn't amount to
+;;; changing the exit target, since the control destination of an exit
+;;; is determined by the block successor; we are just indicating the
+;;; continuation that the result is delivered to.
+;;;
+;;; We then convert the body, using another dummy continuation in its
+;;; own block as the result. After we are done converting the body, we
+;;; move all predecessors of the dummy end block to CONT's block.
+;;;
+;;; Note that we both exploit and maintain the invariant that the CONT
+;;; to an IR1 convert method either has no block or starts the block
+;;; that control should transfer to after completion for the form.
+;;; Nested MV-PROG1's work because during conversion of the result
+;;; form, we use dummy continuation whose block is the true control
+;;; destination.
+(def-ir1-translator multiple-value-prog1 ((result &rest forms) start cont)
+  #!+sb-doc
+  "MULTIPLE-VALUE-PROG1 Values-Form Form*
+  Evaluate Values-Form and then the Forms, but return all the values of
+  Values-Form."
+  (continuation-starts-block cont)
+  (let* ((dummy-result (make-continuation))
+        (dummy-start (make-continuation))
+        (cont-block (continuation-block cont)))
+    (continuation-starts-block dummy-start)
+    (ir1-convert start dummy-start result)
+
+    (substitute-continuation-uses cont dummy-start)
+
+    (continuation-starts-block dummy-result)
+    (ir1-convert-progn-body dummy-start dummy-result forms)
+    (let ((end-block (continuation-block dummy-result)))
+      (dolist (pred (block-pred end-block))
+       (unlink-blocks pred end-block)
+       (link-blocks pred cont-block))
+      (aver (not (continuation-dest dummy-result)))
+      (delete-continuation dummy-result)
+      (remove-from-dfo end-block))))
+\f
+;;;; interface to defining macros
+
+;;;; FIXME:
+;;;;   classic CMU CL comment:
+;;;;     DEFMACRO and DEFUN expand into calls to %DEFxxx functions
+;;;;     so that we get a chance to see what is going on. We define
+;;;;     IR1 translators for these functions which look at the
+;;;;     definition and then generate a call to the %%DEFxxx function.
+;;;; Alas, this implementation doesn't do the right thing for
+;;;; non-toplevel uses of these forms, so this should probably
+;;;; be changed to use EVAL-WHEN instead.
+
+;;; Return a new source path with any stuff intervening between the
+;;; current path and the first form beginning with NAME stripped off.
+;;; This is used to hide the guts of DEFmumble macros to prevent
+;;; annoying error messages.
+(defun revert-source-path (name)
+  (do ((path *current-path* (cdr path)))
+      ((null path) *current-path*)
+    (let ((first (first path)))
+      (when (or (eq first name)
+               (eq first 'original-source-start))
+       (return path)))))
+
+;;; Warn about incompatible or illegal definitions and add the macro
+;;; to the compiler environment.
+;;;
+;;; Someday we could check for macro arguments being incompatibly
+;;; redefined. Doing this right will involve finding the old macro
+;;; lambda-list and comparing it with the new one.
+(def-ir1-translator %defmacro ((qname qdef lambda-list doc) start cont
+                              :kind :function)
+  (let (;; QNAME is typically a quoted name. I think the idea is to
+       ;; let %DEFMACRO work as an ordinary function when
+       ;; interpreting. Whatever the reason the quote is there, we
+       ;; don't want it any more. -- WHN 19990603
+       (name (eval qname))
+       ;; QDEF should be a sharp-quoted definition. We don't want to
+       ;; make a function of it just yet, so we just drop the
+       ;; sharp-quote.
+       (def (progn
+              (aver (eq 'function (first qdef)))
+              (aver (proper-list-of-length-p qdef 2))
+              (second qdef))))
+
+    (/show "doing IR1 translator for %DEFMACRO" name)
+
+    (unless (symbolp name)
+      (compiler-error "The macro name ~S is not a symbol." name))
+
+    (ecase (info :function :kind name)
+      ((nil))
+      (:function
+       (remhash name *free-functions*)
+       (undefine-function-name name)
+       (compiler-warning
+       "~S is being redefined as a macro when it was ~
+         previously ~(~A~) to be a function."
+       name
+       (info :function :where-from name)))
+      (:macro)
+      (:special-form
+       (compiler-error "The special form ~S can't be redefined as a macro."
+                      name)))
+
+    (setf (info :function :kind name) :macro
+         (info :function :where-from name) :defined
+         (info :function :macro-function name) (coerce def 'function))
+
+    (let* ((*current-path* (revert-source-path 'defmacro))
+          (fun (ir1-convert-lambda def name)))
+      (setf (leaf-name fun)
+           (concatenate 'string "DEFMACRO " (symbol-name name)))
+      (setf (functional-arg-documentation fun) (eval lambda-list))
+
+      (ir1-convert start cont `(%%defmacro ',name ,fun ,doc)))
+
+    (when sb!xc:*compile-print*
+      ;; FIXME: It would be nice to convert this, and the other places
+      ;; which create compiler diagnostic output prefixed by
+      ;; semicolons, to use some common utility which automatically
+      ;; prefixes all its output with semicolons. (The addition of
+      ;; semicolon prefixes was introduced ca. sbcl-0.6.8.10 as the
+      ;; "MNA compiler message patch", and implemented by modifying a
+      ;; bunch of output statements on a case-by-case basis, which
+      ;; seems unnecessarily error-prone and unclear, scattering
+      ;; implicit information about output style throughout the
+      ;; system.) Starting by rewriting COMPILER-MUMBLE to add
+      ;; semicolon prefixes would be a good start, and perhaps also:
+      ;;   * Add semicolon prefixes for "FOO assembled" messages emitted 
+      ;;     when e.g. src/assembly/x86/assem-rtns.lisp is processed.
+      ;;   * At least some debugger output messages deserve semicolon
+      ;;     prefixes too:
+      ;;     ** restarts table
+      ;;     ** "Within the debugger, you can type HELP for help."
+      (compiler-mumble "~&; converted ~S~%" name))))
+
+(def-ir1-translator %define-compiler-macro ((name def lambda-list doc)
+                                           start cont
+                                           :kind :function)
+  (let ((name (eval name))
+       (def (second def))) ; We don't want to make a function just yet...
+
+    (when (eq (info :function :kind name) :special-form)
+      (compiler-error "attempt to define a compiler-macro for special form ~S"
+                     name))
+
+    (setf (info :function :compiler-macro-function name)
+         (coerce def 'function))
+
+    (let* ((*current-path* (revert-source-path 'define-compiler-macro))
+          (fun (ir1-convert-lambda def name)))
+      (setf (leaf-name fun)
+           (let ((*print-case* :upcase))
+             (format nil "DEFINE-COMPILER-MACRO ~S" name)))
+      (setf (functional-arg-documentation fun) (eval lambda-list))
+
+      (ir1-convert start cont `(%%define-compiler-macro ',name ,fun ,doc)))
+
+    (when sb!xc:*compile-print*
+      (compiler-mumble "~&; converted ~S~%" name))))
diff --git a/src/compiler/ir1report.lisp b/src/compiler/ir1report.lisp
new file mode 100644 (file)
index 0000000..bfaab10
--- /dev/null
@@ -0,0 +1,518 @@
+;;;; machinery for reporting errors/warnings/notes/whatnot from
+;;;; the compiler
+
+;;;; 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!C")
+\f
+;;;; compiler error context determination
+
+(declaim (special *current-path*))
+
+;;; We bind print level and length when printing out messages so that
+;;; we don't dump huge amounts of garbage.
+;;;
+;;; FIXME: It's not possible to get the defaults right for everyone.
+;;; So: Should these variables be in the SB-EXT package? Or should we
+;;; just get rid of them completely and just use the bare
+;;; CL:*PRINT-FOO* variables instead?
+(declaim (type (or unsigned-byte null)
+              *compiler-error-print-level*
+              *compiler-error-print-length*
+              *compiler-error-print-lines*))
+(defvar *compiler-error-print-level* 5
+  #!+sb-doc
+  "the value for *PRINT-LEVEL* when printing compiler error messages")
+(defvar *compiler-error-print-length* 10
+  #!+sb-doc
+  "the value for *PRINT-LENGTH* when printing compiler error messages")
+(defvar *compiler-error-print-lines* 12
+  #!+sb-doc
+  "the value for *PRINT-LINES* when printing compiler error messages")
+
+(defvar *enclosing-source-cutoff* 1
+  #!+sb-doc
+  "The maximum number of enclosing non-original source forms (i.e. from
+  macroexpansion) that we print in full. For additional enclosing forms, we
+  print only the CAR.")
+(declaim (type unsigned-byte *enclosing-source-cutoff*))
+
+;;; We separate the determination of compiler error contexts from the
+;;; actual signalling of those errors by objectifying the error
+;;; context. This allows postponement of the determination of how (and
+;;; if) to signal the error.
+;;;
+;;; We take care not to reference any of the IR1 so that pending
+;;; potential error messages won't prevent the IR1 from being GC'd. To
+;;; this end, we convert source forms to strings so that source forms
+;;; that contain IR1 references (e.g. %DEFUN) don't hold onto the IR.
+(defstruct (compiler-error-context
+           #-no-ansi-print-object
+           (:print-object (lambda (x stream)
+                            (print-unreadable-object (x stream :type t))))
+           (:copier nil))
+  ;; a list of the stringified CARs of the enclosing non-original source forms
+  ;; exceeding the *enclosing-source-cutoff*
+  (enclosing-source nil :type list)
+  ;; a list of stringified enclosing non-original source forms
+  (source nil :type list)
+  ;; the stringified form in the original source that expanded into SOURCE
+  (original-source (required-argument) :type simple-string)
+  ;; a list of prefixes of "interesting" forms that enclose original-source
+  (context nil :type list)
+  ;; the FILE-INFO-NAME for the relevant FILE-INFO
+  (file-name (required-argument)
+            :type (or pathname (member :lisp :stream)))
+  ;; the file position at which the top-level form starts, if applicable
+  (file-position nil :type (or index null))
+  ;; the original source part of the source path
+  (original-source-path nil :type list))
+
+;;; If true, this is the node which is used as context in compiler warning
+;;; messages.
+(declaim (type (or null compiler-error-context node) *compiler-error-context*))
+(defvar *compiler-error-context* nil)
+
+;;; a hashtable mapping macro names to source context parsers. Each parser
+;;; function returns the source-context list for that form.
+(defvar *source-context-methods* (make-hash-table))
+
+;;; documentation originally from cmu-user.tex:
+;;;   This macro defines how to extract an abbreviated source context from
+;;;   the \var{name}d form when it appears in the compiler input.
+;;;   \var{lambda-list} is a \code{defmacro} style lambda-list used to
+;;;   parse the arguments. The \var{body} should return a list of
+;;;   subforms that can be printed on about one line. There are
+;;;   predefined methods for \code{defstruct}, \code{defmethod}, etc. If
+;;;   no method is defined, then the first two subforms are returned.
+;;;   Note that this facility implicitly determines the string name
+;;;   associated with anonymous functions.
+;;; So even though SBCL itself only uses this macro within this file,
+;;; it's a reasonable thing to put in SB-EXT in case some dedicated
+;;; user wants to do some heavy tweaking to make SBCL give more
+;;; informative output about his code.
+(defmacro def-source-context (name lambda-list &body body)
+  #!+sb-doc
+  "DEF-SOURCE-CONTEXT Name Lambda-List Form*
+   This macro defines how to extract an abbreviated source context from the
+   Named form when it appears in the compiler input. Lambda-List is a DEFMACRO
+   style lambda-list used to parse the arguments. The Body should return a
+   list of subforms suitable for a \"~{~S ~}\" format string."
+  (let ((n-whole (gensym)))
+    `(setf (gethash ',name *source-context-methods*)
+          #'(lambda (,n-whole)
+              (destructuring-bind ,lambda-list ,n-whole ,@body)))))
+
+(def-source-context defstruct (name-or-options &rest slots)
+  (declare (ignore slots))
+  `(defstruct ,(if (consp name-or-options)
+                  (car name-or-options)
+                  name-or-options)))
+
+(def-source-context function (thing)
+  (if (and (consp thing) (eq (first thing) 'lambda) (consp (rest thing)))
+      `(lambda ,(second thing))
+      `(function ,thing)))
+
+;;; Return the first two elements of FORM if FORM is a list. Take the
+;;; CAR of the second form if appropriate.
+(defun source-form-context (form)
+  (cond ((atom form) nil)
+       ((>= (length form) 2)
+        (funcall (gethash (first form) *source-context-methods*
+                          #'(lambda (x)
+                              (declare (ignore x))
+                              (list (first form) (second form))))
+                 (rest form)))
+       (t
+        form)))
+
+;;; Given a source path, return the original source form and a
+;;; description of the interesting aspects of the context in which it
+;;; appeared. The context is a list of lists, one sublist per context
+;;; form. The sublist is a list of some of the initial subforms of the
+;;; context form.
+;;;
+;;; For now, we use the first two subforms of each interesting form. A
+;;; form is interesting if the first element is a symbol beginning
+;;; with "DEF" and it is not the source form. If there is no
+;;; DEF-mumble, then we use the outermost containing form. If the
+;;; second subform is a list, then in some cases we return the CAR of
+;;; that form rather than the whole form (i.e. don't show DEFSTRUCT
+;;; options, etc.)
+(defun find-original-source (path)
+  (declare (list path))
+  (let* ((rpath (reverse (source-path-original-source path)))
+        (tlf (first rpath))
+        (root (find-source-root tlf *source-info*)))
+    (collect ((context))
+      (let ((form root)
+           (current (rest rpath)))
+       (loop
+         (when (atom form)
+           (aver (null current))
+           (return))
+         (let ((head (first form)))
+           (when (symbolp head)
+             (let ((name (symbol-name head)))
+               (when (and (>= (length name) 3) (string= name "DEF" :end1 3))
+                 (context (source-form-context form))))))
+         (when (null current) (return))
+         (setq form (nth (pop current) form)))
+       
+       (cond ((context)
+              (values form (context)))
+             ((and path root)
+              (let ((c (source-form-context root)))
+                (values form (if c (list c) nil))))
+             (t
+              (values '(unable to locate source)
+                      '((some strange place)))))))))
+
+;;; Convert a source form to a string, suitably formatted for use in
+;;; compiler warnings.
+(defun stringify-form (form &optional (pretty t))
+  (let ((*print-level* *compiler-error-print-level*)
+       (*print-length* *compiler-error-print-length*)
+       (*print-lines* *compiler-error-print-lines*)
+       (*print-pretty* pretty))
+    (if pretty
+       (format nil "~<~@;  ~S~:>" (list form))
+       (prin1-to-string form))))
+
+;;; Return a COMPILER-ERROR-CONTEXT structure describing the current
+;;; error context, or NIL if we can't figure anything out. ARGS is a
+;;; list of things that are going to be printed out in the error
+;;; message, and can thus be blown off when they appear in the source
+;;; context.
+(defun find-error-context (args)
+  (let ((context *compiler-error-context*))
+    (if (compiler-error-context-p context)
+       context
+       (let ((path (or (and (boundp '*current-path*) *current-path*)
+                       (if context
+                           (node-source-path context)
+                           nil))))
+         (when (and *source-info* path)
+           (multiple-value-bind (form src-context) (find-original-source path)
+             (collect ((full nil cons)
+                       (short nil cons))
+               (let ((forms (source-path-forms path))
+                     (n 0))
+                 (dolist (src (if (member (first forms) args)
+                                  (rest forms)
+                                  forms))
+                   (if (>= n *enclosing-source-cutoff*)
+                       (short (stringify-form (if (consp src)
+                                                  (car src)
+                                                  src)
+                                              nil))
+                       (full (stringify-form src)))
+                   (incf n)))
+
+               (let* ((tlf (source-path-tlf-number path))
+                      (file-info (source-info-file-info *source-info*)))
+                 (make-compiler-error-context
+                  :enclosing-source (short)
+                  :source (full)
+                  :original-source (stringify-form form)
+                  :context src-context
+                  :file-name (file-info-name file-info)
+                  :file-position
+                  (multiple-value-bind (ignore pos)
+                      (find-source-root tlf *source-info*)
+                    (declare (ignore ignore))
+                    pos)
+                  :original-source-path
+                  (source-path-original-source path))))))))))
+\f
+;;;; printing error messages
+
+;;; We save the context information that we printed out most recently
+;;; so that we don't print it out redundantly.
+
+;;; The last COMPILER-ERROR-CONTEXT that we printed.
+(defvar *last-error-context* nil)
+(declaim (type (or compiler-error-context null) *last-error-context*))
+
+;;; The format string and args for the last error we printed.
+(defvar *last-format-string* nil)
+(defvar *last-format-args* nil)
+(declaim (type (or string null) *last-format-string*))
+(declaim (type list *last-format-args*))
+
+;;; The number of times that the last error message has been emitted,
+;;; so that we can compress duplicate error messages.
+(defvar *last-message-count* 0)
+(declaim (type index *last-message-count*))
+
+;;; If the last message was given more than once, then print out an
+;;; indication of how many times it was repeated. We reset the message
+;;; count when we are done.
+(defun note-message-repeats (&optional (terpri t))
+  (cond ((= *last-message-count* 1)
+        (when terpri (terpri *error-output*)))
+       ((> *last-message-count* 1)
+          (format *error-output* "~&; [Last message occurs ~D times.]~2%"
+                *last-message-count*)))
+  (setq *last-message-count* 0))
+
+;;; Print out the message, with appropriate context if we can find it.
+;;; If the context is different from the context of the last message
+;;; we printed, then we print the context. If the original source is
+;;; different from the source we are working on, then we print the
+;;; current source in addition to the original source.
+;;;
+;;; We suppress printing of messages identical to the previous, but
+;;; record the number of times that the message is repeated.
+(defun print-compiler-message (format-string format-args)
+
+  (declare (type simple-string format-string))
+  (declare (type list format-args))
+  
+  (let ((stream *error-output*)
+       (context (find-error-context format-args)))
+    (cond
+     (context
+      (let ((file (compiler-error-context-file-name context))
+           (in (compiler-error-context-context context))
+           (form (compiler-error-context-original-source context))
+           (enclosing (compiler-error-context-enclosing-source context))
+           (source (compiler-error-context-source context))
+           (last *last-error-context*))
+
+       (unless (and last
+                    (equal file (compiler-error-context-file-name last)))
+         (when (pathnamep file)
+           (note-message-repeats)
+           (setq last nil)
+            (format stream "~2&; file: ~A~%" (namestring file))))
+
+       (unless (and last
+                    (equal in (compiler-error-context-context last)))
+         (note-message-repeats)
+         (setq last nil)
+          (format stream "~&")
+          (pprint-logical-block (stream nil :per-line-prefix "; ")
+            (format stream "in:~{~<~%    ~4:;~{ ~S~}~>~^ =>~}" in))
+          (format stream "~%"))
+
+
+       (unless (and last
+                    (string= form
+                             (compiler-error-context-original-source last)))
+         (note-message-repeats)
+         (setq last nil)
+          (format stream "~&")
+          (pprint-logical-block (stream nil :per-line-prefix "; ")
+            (format stream "  ~A" form))
+          (format stream "~&"))
+
+       (unless (and last
+                    (equal enclosing
+                           (compiler-error-context-enclosing-source last)))
+         (when enclosing
+           (note-message-repeats)
+           (setq last nil)
+           (format stream "~&; --> ~{~<~%; --> ~1:;~A~> ~}~%" enclosing)))
+
+       (unless (and last
+                    (equal source (compiler-error-context-source last)))
+         (setq *last-format-string* nil)
+         (when source
+           (note-message-repeats)
+           (dolist (src source)
+              (format stream "~&")
+              (write-string "; ==>" stream)
+              (format stream "~&")
+              (pprint-logical-block (stream nil :per-line-prefix "; ")
+                (write-string src stream)))))))
+     (t
+       (format stream "~&")
+      (note-message-repeats)
+      (setq *last-format-string* nil)
+       (format stream "~&")))
+
+    (setq *last-error-context* context)
+
+    (unless (and (equal format-string *last-format-string*)
+                (tree-equal format-args *last-format-args*))
+      (note-message-repeats nil)
+      (setq *last-format-string* format-string)
+      (setq *last-format-args* format-args)
+      (let ((*print-level*  *compiler-error-print-level*)
+           (*print-length* *compiler-error-print-length*)
+           (*print-lines*  *compiler-error-print-lines*))
+        (format stream "~&")
+        (pprint-logical-block (stream nil :per-line-prefix "; ")
+          (format stream "~&~?" format-string format-args))
+        (format stream "~&"))))
+
+  (incf *last-message-count*)
+  (values))
+
+(defun print-compiler-condition (condition)
+  (declare (type condition condition))
+  (let (;; These different classes of conditions have different
+       ;; effects on the return codes of COMPILE-FILE, so it's nice
+       ;; for users to be able to pick them out by lexical search
+       ;; through the output.
+       (what (etypecase condition
+               (style-warning 'style-warning)
+               (warning 'warning)
+               (error 'error))))
+    (multiple-value-bind (format-string format-args)
+       (if (typep condition 'simple-condition)
+           (values (simple-condition-format-control condition)
+                   (simple-condition-format-arguments condition))
+           (values "~A"
+                   (list (with-output-to-string (s)
+                           (princ condition s)))))
+      (print-compiler-message (format nil
+                                     "caught ~S:~%  ~A"
+                                     what
+                                     format-string)
+                             format-args)))
+  (values))
+
+;;; COMPILER-NOTE is vaguely like COMPILER-ERROR and the other
+;;; condition-signalling functions, but it just writes some output
+;;; instead of signalling. (In CMU CL, it did signal a condition, but
+;;; this didn't seem to work all that well; it was weird to have
+;;; COMPILE-FILE return with WARNINGS-P set when the only problem was
+;;; that the compiler couldn't figure out how to compile something as
+;;; efficiently as it liked.)
+(defun compiler-note (format-string &rest format-args)
+  (unless (if *compiler-error-context*
+             (policy *compiler-error-context* (= inhibit-warnings 3))
+             (policy *lexenv* (= inhibit-warnings 3)))
+    (incf *compiler-note-count*)
+    (print-compiler-message (format nil "note: ~A" format-string)
+                           format-args))
+  (values))
+
+;;; Issue a note when we might or might not be in the compiler.
+(defun maybe-compiler-note (&rest rest)
+  (if (boundp '*lexenv*) ; if we're in the compiler
+      (apply #'compiler-note rest)
+      (let ((stream *error-output*))
+       (pprint-logical-block (stream nil :per-line-prefix ";")
+         
+         (format stream " note: ~3I~_")
+         (pprint-logical-block (stream nil)
+           (apply #'format stream rest)))
+       (fresh-line stream)))) ; (outside logical block, no per-line-prefix)
+
+;;; The politically correct way to print out progress messages and
+;;; such like. We clear the current error context so that we know that
+;;; it needs to be reprinted, and we also Force-Output so that the
+;;; message gets seen right away.
+(declaim (ftype (function (string &rest t) (values)) compiler-mumble))
+(defun compiler-mumble (format-string &rest format-args)
+  (note-message-repeats)
+  (setq *last-error-context* nil)
+  (apply #'format *error-output* format-string format-args)
+  (force-output *error-output*)
+  (values))
+
+;;; Return a string that somehow names the code in COMPONENT. We use
+;;; the source path for the bind node for an arbitrary entry point to
+;;; find the source context, then return that as a string.
+(declaim (ftype (function (component) simple-string) find-component-name))
+(defun find-component-name (component)
+  (let ((ep (first (block-succ (component-head component)))))
+    (aver ep) ; else no entry points??
+    (multiple-value-bind (form context)
+       (find-original-source
+        (node-source-path (continuation-next (block-start ep))))
+      (declare (ignore form))
+      (let ((*print-level* 2)
+           (*print-pretty* nil))
+       (format nil "~{~{~S~^ ~}~^ => ~}" context)))))
+\f
+;;;; condition system interface
+
+;;; Keep track of how many times each kind of condition happens.
+(defvar *compiler-error-count*)
+(defvar *compiler-warning-count*)
+(defvar *compiler-style-warning-count*)
+(defvar *compiler-note-count*)
+
+;;; Keep track of whether any surrounding COMPILE or COMPILE-FILE call
+;;; should return WARNINGS-P or FAILURE-P.
+(defvar *failure-p*)
+(defvar *warnings-p*)
+
+;;; condition handlers established by the compiler. We re-signal the
+;;; condition, then if it isn't handled, we increment our warning
+;;; counter and print the error message.
+(defun compiler-error-handler (condition)
+  (signal condition)
+  (incf *compiler-error-count*)
+  (setf *warnings-p* t
+       *failure-p* t)
+  (print-compiler-condition condition)
+  (continue condition))
+(defun compiler-warning-handler (condition)
+  (signal condition)
+  (incf *compiler-warning-count*)
+  (setf *warnings-p* t
+       *failure-p* t)
+  (print-compiler-condition condition)
+  (muffle-warning condition))
+(defun compiler-style-warning-handler (condition)
+  (signal condition)
+  (incf *compiler-style-warning-count*)
+  (setf *warnings-p* t)
+  (print-compiler-condition condition)
+  (muffle-warning condition))
+\f
+;;;; undefined warnings
+
+(defvar *undefined-warning-limit* 3
+  #!+sb-doc
+  "If non-null, then an upper limit on the number of unknown function or type
+  warnings that the compiler will print for any given name in a single
+  compilation. This prevents excessive amounts of output when the real
+  problem is a missing definition (as opposed to a typo in the use.)")
+
+;;; Make an entry in the *UNDEFINED-WARNINGS* describing a reference
+;;; to NAME of the specified KIND. If we have exceeded the warning
+;;; limit, then just increment the count, otherwise note the current
+;;; error context.
+;;;
+;;; Undefined types are noted by a condition handler in
+;;; WITH-COMPILATION-UNIT, which can potentially be invoked outside
+;;; the compiler, hence the BOUNDP check.
+(defun note-undefined-reference (name kind)
+  (unless (and
+          ;; Check for boundness so we don't blow up if we're called
+          ;; when IR1 conversion isn't going on.
+          (boundp '*lexenv*)
+          ;; FIXME: I'm pretty sure the INHIBIT-WARNINGS test below
+          ;; isn't a good idea; we should have INHIBIT-WARNINGS
+          ;; affect compiler notes, not STYLE-WARNINGs. And I'm not
+          ;; sure what the BOUNDP '*LEXENV* test above is for; it's
+          ;; likely a good idea, but it probably deserves an
+          ;; explanatory comment.
+          (policy *lexenv* (= inhibit-warnings 3)))
+    (let* ((found (dolist (warning *undefined-warnings* nil)
+                   (when (and (equal (undefined-warning-name warning) name)
+                              (eq (undefined-warning-kind warning) kind))
+                     (return warning))))
+          (res (or found
+                   (make-undefined-warning :name name :kind kind))))
+      (unless found (push res *undefined-warnings*))
+      (when (or (not *undefined-warning-limit*)
+               (< (undefined-warning-count res) *undefined-warning-limit*))
+       (push (find-error-context (list name))
+             (undefined-warning-warnings res)))
+      (incf (undefined-warning-count res))))
+  (values))
index 45f95c6..a51ab3a 100644 (file)
@@ -23,7 +23,7 @@
 (declaim (hash-table *source-paths*))
 (defvar *source-paths*)
 
-;;; *CURRENT-COMPONENT* is the Component structure which we link
+;;; *CURRENT-COMPONENT* is the COMPONENT structure which we link
 ;;; blocks into as we generate them. This just serves to glue the
 ;;; emitted blocks together until local call analysis and flow graph
 ;;; canonicalization figure out what is really going on. We need to
        (setf (leaf-name res) name)
        res))))
 \f
-;;; FIXME: This file is rather long, and contains two distinct sections,
-;;; transform machinery above this point and transforms themselves below this
-;;; point. Why not split it in two? (ir1translate.lisp and
-;;; ir1translators.lisp?) Then consider byte-compiling the translators, too.
-\f
-;;;; control special forms
-
-(def-ir1-translator progn ((&rest forms) start cont)
-  #!+sb-doc
-  "Progn Form*
-  Evaluates each Form in order, returning the values of the last form. With no
-  forms, returns NIL."
-  (ir1-convert-progn-body start cont forms))
-
-(def-ir1-translator if ((test then &optional else) start cont)
-  #!+sb-doc
-  "If Predicate Then [Else]
-  If Predicate evaluates to non-null, evaluate Then and returns its values,
-  otherwise evaluate Else and return its values. Else defaults to NIL."
-  (let* ((pred (make-continuation))
-        (then-cont (make-continuation))
-        (then-block (continuation-starts-block then-cont))
-        (else-cont (make-continuation))
-        (else-block (continuation-starts-block else-cont))
-        (dummy-cont (make-continuation))
-        (node (make-if :test pred
-                       :consequent then-block
-                       :alternative else-block)))
-    (setf (continuation-dest pred) node)
-    (ir1-convert start pred test)
-    (prev-link node pred)
-    (use-continuation node dummy-cont)
-
-    (let ((start-block (continuation-block pred)))
-      (setf (block-last start-block) node)
-      (continuation-starts-block cont)
-
-      (link-blocks start-block then-block)
-      (link-blocks start-block else-block)
-
-      (ir1-convert then-cont cont then)
-      (ir1-convert else-cont cont else))))
-\f
-;;;; BLOCK and TAGBODY
-
-;;;; We make an Entry node to mark the start and a :Entry cleanup to
-;;;; mark its extent. When doing GO or RETURN-FROM, we emit an Exit
-;;;; node.
-
-;;; Make a :ENTRY cleanup and emit an ENTRY node, then convert the
-;;; body in the modified environment. We make CONT start a block now,
-;;; since if it was done later, the block would be in the wrong
-;;; environment.
-(def-ir1-translator block ((name &rest forms) start cont)
-  #!+sb-doc
-  "Block Name Form*
-  Evaluate the Forms as a PROGN. Within the lexical scope of the body,
-  (RETURN-FROM Name Value-Form) can be used to exit the form, returning the
-  result of Value-Form."
-  (unless (symbolp name)
-    (compiler-error "The block name ~S is not a symbol." name))
-  (continuation-starts-block cont)
-  (let* ((dummy (make-continuation))
-        (entry (make-entry))
-        (cleanup (make-cleanup :kind :block
-                               :mess-up entry)))
-    (push entry (lambda-entries (lexenv-lambda *lexenv*)))
-    (setf (entry-cleanup entry) cleanup)
-    (prev-link entry start)
-    (use-continuation entry dummy)
-    
-    (let* ((env-entry (list entry cont))
-           (*lexenv* (make-lexenv :blocks (list (cons name env-entry))
-                                 :cleanup cleanup)))
-      (push env-entry (continuation-lexenv-uses cont))
-      (ir1-convert-progn-body dummy cont forms))))
-
-
-;;; We make CONT start a block just so that it will have a block
-;;; assigned. People assume that when they pass a continuation into
-;;; IR1-CONVERT as CONT, it will have a block when it is done.
-(def-ir1-translator return-from ((name &optional value)
-                                start cont)
-  #!+sb-doc
-  "Return-From Block-Name Value-Form
-  Evaluate the Value-Form, returning its values from the lexically enclosing
-  BLOCK Block-Name. This is constrained to be used only within the dynamic
-  extent of the BLOCK."
-  (continuation-starts-block cont)
-  (let* ((found (or (lexenv-find name blocks)
-                   (compiler-error "return for unknown block: ~S" name)))
-        (value-cont (make-continuation))
-        (entry (first found))
-        (exit (make-exit :entry entry
-                         :value value-cont)))
-    (push exit (entry-exits entry))
-    (setf (continuation-dest value-cont) exit)
-    (ir1-convert start value-cont value)
-    (prev-link exit value-cont)
-    (use-continuation exit (second found))))
-
-;;; Return a list of the segments of a TAGBODY. Each segment looks
-;;; like (<tag> <form>* (go <next tag>)). That is, we break up the
-;;; tagbody into segments of non-tag statements, and explicitly
-;;; represent the drop-through with a GO. The first segment has a
-;;; dummy NIL tag, since it represents code before the first tag. The
-;;; last segment (which may also be the first segment) ends in NIL
-;;; rather than a GO.
-(defun parse-tagbody (body)
-  (declare (list body))
-  (collect ((segments))
-    (let ((current (cons nil body)))
-      (loop
-       (let ((tag-pos (position-if (complement #'listp) current :start 1)))
-         (unless tag-pos
-           (segments `(,@current nil))
-           (return))
-         (let ((tag (elt current tag-pos)))
-           (when (assoc tag (segments))
-             (compiler-error
-              "The tag ~S appears more than once in the tagbody."
-              tag))
-           (unless (or (symbolp tag) (integerp tag))
-             (compiler-error "~S is not a legal tagbody statement." tag))
-           (segments `(,@(subseq current 0 tag-pos) (go ,tag))))
-         (setq current (nthcdr tag-pos current)))))
-    (segments)))
-
-;;; Set up the cleanup, emitting the entry node. Then make a block for
-;;; each tag, building up the tag list for LEXENV-TAGS as we go.
-;;; Finally, convert each segment with the precomputed Start and Cont
-;;; values.
-(def-ir1-translator tagbody ((&rest statements) start cont)
-  #!+sb-doc
-  "Tagbody {Tag | Statement}*
-  Define tags for used with GO. The Statements are evaluated in order
-  (skipping Tags) and NIL is returned. If a statement contains a GO to a
-  defined Tag within the lexical scope of the form, then control is transferred
-  to the next statement following that tag. A Tag must an integer or a
-  symbol. A statement must be a list. Other objects are illegal within the
-  body."
-  (continuation-starts-block cont)
-  (let* ((dummy (make-continuation))
-        (entry (make-entry))
-        (segments (parse-tagbody statements))
-        (cleanup (make-cleanup :kind :tagbody
-                               :mess-up entry)))
-    (push entry (lambda-entries (lexenv-lambda *lexenv*)))
-    (setf (entry-cleanup entry) cleanup)
-    (prev-link entry start)
-    (use-continuation entry dummy)
-
-    (collect ((tags)
-             (starts)
-             (conts))
-      (starts dummy)
-      (dolist (segment (rest segments))
-       (let* ((tag-cont (make-continuation))
-               (tag (list (car segment) entry tag-cont)))          
-         (conts tag-cont)
-         (starts tag-cont)
-         (continuation-starts-block tag-cont)
-          (tags tag)
-          (push (cdr tag) (continuation-lexenv-uses tag-cont))))
-      (conts cont)
-
-      (let ((*lexenv* (make-lexenv :cleanup cleanup :tags (tags))))
-       (mapc (lambda (segment start cont)
-               (ir1-convert-progn-body start cont (rest segment)))
-             segments (starts) (conts))))))
-
-;;; Emit an EXIT node without any value.
-(def-ir1-translator go ((tag) start cont)
-  #!+sb-doc
-  "Go Tag
-  Transfer control to the named Tag in the lexically enclosing TAGBODY. This
-  is constrained to be used only within the dynamic extent of the TAGBODY."
-  (continuation-starts-block cont)
-  (let* ((found (or (lexenv-find tag tags :test #'eql)
-                   (compiler-error "Go to nonexistent tag: ~S." tag)))
-        (entry (first found))
-        (exit (make-exit :entry entry)))
-    (push exit (entry-exits entry))
-    (prev-link exit start)
-    (use-continuation exit (second found))))
-\f
-;;;; translators for compiler-magic special forms
-
-;;; This handles EVAL-WHEN in non-top-level forms. (EVAL-WHENs in
-;;; top-level forms are picked off and handled by PROCESS-TOP-LEVEL-FORM,
-;;; so that they're never seen at this level.)
-;;;
-;;; ANSI "3.2.3.1 Processing of Top Level Forms" says that processing
-;;; of non-top-level EVAL-WHENs is very simple:
-;;;   EVAL-WHEN forms cause compile-time evaluation only at top level.
-;;;   Both :COMPILE-TOPLEVEL and :LOAD-TOPLEVEL situation specifications
-;;;   are ignored for non-top-level forms. For non-top-level forms, an
-;;;   eval-when specifying the :EXECUTE situation is treated as an
-;;;   implicit PROGN including the forms in the body of the EVAL-WHEN
-;;;   form; otherwise, the forms in the body are ignored. 
-(def-ir1-translator eval-when ((situations &rest forms) start cont)
-  #!+sb-doc
-  "EVAL-WHEN (Situation*) Form*
-  Evaluate the Forms in the specified Situations (any of :COMPILE-TOPLEVEL,
-  :LOAD-TOPLEVEL, or :EXECUTE, or (deprecated) COMPILE, LOAD, or EVAL)."
-  (multiple-value-bind (ct lt e) (parse-eval-when-situations situations)
-    (declare (ignore ct lt))
-    (ir1-convert-progn-body start cont (and e forms)))
-  (values))
-
-;;; common logic for MACROLET and SYMBOL-MACROLET
-;;;
-;;; Call DEFINITIONIZE-FUN on each element of DEFINITIONS to find its
-;;; in-lexenv representation, stuff the results into *LEXENV*, and
-;;; call FUN (with no arguments).
-(defun %funcall-in-foomacrolet-lexenv (definitionize-fun
-                                      definitionize-keyword
-                                      definitions
-                                      fun)
-  (declare (type function definitionize-fun fun))
-  (declare (type (member :variables :functions) definitionize-keyword))
-  (declare (type list definitions))
-  (unless (= (length definitions)
-             (length (remove-duplicates definitions :key #'first)))
-    (compiler-style-warning "duplicate definitions in ~S" definitions))
-  (let* ((processed-definitions (mapcar definitionize-fun definitions))
-         (*lexenv* (make-lexenv definitionize-keyword processed-definitions)))
-    (funcall fun)))
-
-;;; Tweak *LEXENV* to include the DEFINITIONS from a MACROLET, then
-;;; call FUN (with no arguments).
-;;;
-;;; This is split off from the IR1 convert method so that it can be
-;;; shared by the special-case top-level MACROLET processing code.
-(defun funcall-in-macrolet-lexenv (definitions fun)
-  (%funcall-in-foomacrolet-lexenv
-   (lambda (definition)
-     (unless (list-of-length-at-least-p definition 2)
-       (compiler-error
-       "The list ~S is too short to be a legal local macro definition."
-       definition))
-     (destructuring-bind (name arglist &body body) definition
-       (unless (symbolp name)
-        (compiler-error "The local macro name ~S is not a symbol." name))
-       (let ((whole (gensym "WHOLE"))
-            (environment (gensym "ENVIRONMENT")))
-        (multiple-value-bind (body local-decls)
-            (parse-defmacro arglist whole body name 'macrolet
-                            :environment environment)
-          `(,name macro .
-                  ,(compile nil
-                            `(lambda (,whole ,environment)
-                               ,@local-decls
-                               (block ,name ,body))))))))
-   :functions
-   definitions
-   fun))
-
-(def-ir1-translator macrolet ((definitions &rest body) start cont)
-  #!+sb-doc
-  "MACROLET ({(Name Lambda-List Form*)}*) Body-Form*
-  Evaluate the Body-Forms in an environment with the specified local macros
-  defined. Name is the local macro name, Lambda-List is the DEFMACRO style
-  destructuring lambda list, and the Forms evaluate to the expansion. The
-  Forms are evaluated in the null environment."
-  (funcall-in-macrolet-lexenv definitions
-                             (lambda ()
-                               (ir1-translate-locally body start cont))))
-
-(defun funcall-in-symbol-macrolet-lexenv (definitions fun)
-  (%funcall-in-foomacrolet-lexenv
-   (lambda (definition)
-     (unless (proper-list-of-length-p definition 2)
-       (compiler-error "malformed symbol/expansion pair: ~S" definition))
-     (destructuring-bind (name expansion) definition
-       (unless (symbolp name)
-         (compiler-error
-          "The local symbol macro name ~S is not a symbol."
-          name))
-       `(,name . (MACRO . ,expansion))))
-   :variables
-   definitions
-   fun))
-  
-(def-ir1-translator symbol-macrolet ((macrobindings &body body) start cont)
-  #!+sb-doc
-  "SYMBOL-MACROLET ({(Name Expansion)}*) Decl* Form*
-  Define the Names as symbol macros with the given Expansions. Within the
-  body, references to a Name will effectively be replaced with the Expansion."
-  (funcall-in-symbol-macrolet-lexenv
-   macrobindings
-   (lambda ()
-     (ir1-translate-locally body start cont))))
-
-;;; not really a special form, but..
-(def-ir1-translator declare ((&rest stuff) start cont)
-  (declare (ignore stuff))
-  ;; We ignore START and CONT too, but we can't use DECLARE IGNORE to
-  ;; tell the compiler about it here, because the DEF-IR1-TRANSLATOR
-  ;; macro would put the DECLARE in the wrong place, so..
-  start cont
-  (compiler-error "misplaced declaration"))
-\f
-;;;; %PRIMITIVE
-;;;;
-;;;; Uses of %PRIMITIVE are either expanded into Lisp code or turned
-;;;; into a funny function.
-
-;;; Carefully evaluate a list of forms, returning a list of the results.
-(defun eval-info-args (args)
-  (declare (list args))
-  (handler-case (mapcar #'eval args)
-    (error (condition)
-      (compiler-error "Lisp error during evaluation of info args:~%~A"
-                     condition))))
-
-;;; If there is a primitive translator, then we expand the call.
-;;; Otherwise, we convert to the %%PRIMITIVE funny function. The first
-;;; argument is the template, the second is a list of the results of
-;;; any codegen-info args, and the remaining arguments are the runtime
-;;; arguments.
-;;;
-;;; We do a bunch of error checking now so that we don't bomb out with
-;;; a fatal error during IR2 conversion.
-;;;
-;;; KLUDGE: It's confusing having multiple names floating around for
-;;; nearly the same concept: PRIMITIVE, TEMPLATE, VOP. Now that CMU
-;;; CL's *PRIMITIVE-TRANSLATORS* stuff is gone, we could call
-;;; primitives VOPs, rename TEMPLATE to VOP-TEMPLATE, rename
-;;; BACKEND-TEMPLATE-NAMES to BACKEND-VOPS, and rename %PRIMITIVE to
-;;; VOP or %VOP.. -- WHN 2001-06-11
-;;; FIXME: Look at doing this ^, it doesn't look too hard actually.
-(def-ir1-translator %primitive ((name &rest args) start cont)
-  (unless (symbolp name)
-    (compiler-error "The primitive name ~S is not a symbol." name))
-
-  (let* ((template (or (gethash name *backend-template-names*)
-                      (compiler-error
-                       "The primitive name ~A is not defined."
-                       name)))
-        (required (length (template-arg-types template)))
-        (info (template-info-arg-count template))
-        (min (+ required info))
-        (nargs (length args)))
-    (if (template-more-args-type template)
-       (when (< nargs min)
-         (compiler-error "Primitive ~A was called with ~R argument~:P, ~
-                          but wants at least ~R."
-                         name
-                         nargs
-                         min))
-       (unless (= nargs min)
-         (compiler-error "Primitive ~A was called with ~R argument~:P, ~
-                          but wants exactly ~R."
-                         name
-                         nargs
-                         min)))
-
-    (when (eq (template-result-types template) :conditional)
-      (compiler-error
-       "%PRIMITIVE was used with a conditional template."))
-
-    (when (template-more-results-type template)
-      (compiler-error
-       "%PRIMITIVE was used with an unknown values template."))
-
-    (ir1-convert start
-                cont
-                `(%%primitive ',template
-                              ',(eval-info-args
-                                 (subseq args required min))
-                              ,@(subseq args 0 required)
-                              ,@(subseq args min)))))
-\f
-;;;; QUOTE and FUNCTION
-
-(def-ir1-translator quote ((thing) start cont)
-  #!+sb-doc
-  "QUOTE Value
-  Return Value without evaluating it."
-  (reference-constant start cont thing))
-
-(def-ir1-translator function ((thing) start cont)
-  #!+sb-doc
-  "FUNCTION Name
-  Return the lexically apparent definition of the function Name. Name may also
-  be a lambda."
-  (if (consp thing)
-      (case (car thing)
-       ((lambda)
-        (reference-leaf start cont (ir1-convert-lambda thing)))
-       ((setf)
-        (let ((var (find-lexically-apparent-function
-                    thing "as the argument to FUNCTION")))
-          (reference-leaf start cont var)))
-       ((instance-lambda)
-        (let ((res (ir1-convert-lambda `(lambda ,@(cdr thing)))))
-          (setf (getf (functional-plist res) :fin-function) t)
-          (reference-leaf start cont res)))
-       (t
-        (compiler-error "~S is not a legal function name." thing)))
-      (let ((var (find-lexically-apparent-function
-                 thing "as the argument to FUNCTION")))
-       (reference-leaf start cont var))))
-\f
-;;;; FUNCALL
-
-;;; FUNCALL is implemented on %FUNCALL, which can only call functions
-;;; (not symbols). %FUNCALL is used directly in some places where the
-;;; call should always be open-coded even if FUNCALL is :NOTINLINE.
-(deftransform funcall ((function &rest args) * * :when :both)
-  (let ((arg-names (make-gensym-list (length args))))
-    `(lambda (function ,@arg-names)
-       (%funcall ,(if (csubtypep (continuation-type function)
-                                (specifier-type 'function))
-                     'function
-                     '(%coerce-callable-to-function function))
-                ,@arg-names))))
-
-(def-ir1-translator %funcall ((function &rest args) start cont)
-  (let ((fun-cont (make-continuation)))
-    (ir1-convert start fun-cont function)
-    (assert-continuation-type fun-cont (specifier-type 'function))
-    (ir1-convert-combination-args fun-cont cont args)))
-
-;;; This source transform exists to reduce the amount of work for the
-;;; compiler. If the called function is a FUNCTION form, then convert
-;;; directly to %FUNCALL, instead of waiting around for type
-;;; inference.
-(def-source-transform funcall (function &rest args)
-  (if (and (consp function) (eq (car function) 'function))
-      `(%funcall ,function ,@args)
-      (values nil t)))
-
-(deftransform %coerce-callable-to-function ((thing) (function) *
-                                           :when :both
-                                           :important t)
-  "optimize away possible call to FDEFINITION at runtime"
-  'thing)
-\f
-;;;; LET and LET*
-;;;;
-;;;; (LET and LET* can't be implemented as macros due to the fact that
-;;;; any pervasive declarations also affect the evaluation of the
-;;;; arguments.)
-
-;;; Given a list of binding specifiers in the style of Let, return:
-;;;  1. The list of var structures for the variables bound.
-;;;  2. The initial value form for each variable.
-;;;
-;;; The variable names are checked for legality and globally special
-;;; variables are marked as such. Context is the name of the form, for
-;;; error reporting purposes.
-(declaim (ftype (function (list symbol) (values list list list))
-               extract-let-variables))
-(defun extract-let-variables (bindings context)
-  (collect ((vars)
-           (vals)
-           (names))
-    (flet ((get-var (name)
-            (varify-lambda-arg name
-                               (if (eq context 'let*)
-                                   nil
-                                   (names)))))
-      (dolist (spec bindings)
-       (cond ((atom spec)
-              (let ((var (get-var spec)))
-                (vars var)
-                (names (cons spec var))
-                (vals nil)))
-             (t
-              (unless (proper-list-of-length-p spec 1 2)
-                (compiler-error "The ~S binding spec ~S is malformed."
-                                context
-                                spec))
-              (let* ((name (first spec))
-                     (var (get-var name)))
-                (vars var)
-                (names name)
-                (vals (second spec)))))))
-
-    (values (vars) (vals) (names))))
-
-(def-ir1-translator let ((bindings &body body)
-                        start cont)
-  #!+sb-doc
-  "LET ({(Var [Value]) | Var}*) Declaration* Form*
-  During evaluation of the Forms, bind the Vars to the result of evaluating the
-  Value forms. The variables are bound in parallel after all of the Values are
-  evaluated."
-  (multiple-value-bind (forms decls) (sb!sys:parse-body body nil)
-    (multiple-value-bind (vars values) (extract-let-variables bindings 'let)
-      (let* ((*lexenv* (process-decls decls vars nil cont))
-            (fun-cont (make-continuation))
-            (fun (ir1-convert-lambda-body forms vars)))
-       (reference-leaf start fun-cont fun)
-       (ir1-convert-combination-args fun-cont cont values)))))
-
-(def-ir1-translator let* ((bindings &body body)
-                         start cont)
-  #!+sb-doc
-  "LET* ({(Var [Value]) | Var}*) Declaration* Form*
-  Similar to LET, but the variables are bound sequentially, allowing each Value
-  form to reference any of the previous Vars."
-  (multiple-value-bind (forms decls) (sb!sys:parse-body body nil)
-    (multiple-value-bind (vars values) (extract-let-variables bindings 'let*)
-      (let ((*lexenv* (process-decls decls vars nil cont)))
-       (ir1-convert-aux-bindings start cont forms vars values)))))
-
-;;; logic shared between IR1 translators for LOCALLY, MACROLET,
-;;; and SYMBOL-MACROLET
-;;;
-;;; Note that all these things need to preserve top-level-formness,
-;;; but we don't need to worry about that within an IR1 translator,
-;;; since top-level-formness is picked off by PROCESS-TOP-LEVEL-FOO
-;;; forms before we hit the IR1 transform level.
-(defun ir1-translate-locally (body start cont)
-  (declare (type list body) (type continuation start cont))
-  (multiple-value-bind (forms decls) (sb!sys:parse-body body nil)
-    (let ((*lexenv* (process-decls decls nil nil cont)))
-      (ir1-convert-aux-bindings start cont forms nil nil))))
-
-(def-ir1-translator locally ((&body body) start cont)
-  #!+sb-doc
-  "LOCALLY Declaration* Form*
-  Sequentially evaluate the Forms in a lexical environment where the
-  the Declarations have effect. If LOCALLY is a top-level form, then
-  the Forms are also processed as top-level forms."
-  (ir1-translate-locally body start cont))
-\f
-;;;; FLET and LABELS
-
-;;; Given a list of local function specifications in the style of
-;;; FLET, return lists of the function names and of the lambdas which
-;;; are their definitions.
-;;;
-;;; The function names are checked for legality. CONTEXT is the name
-;;; of the form, for error reporting.
-(declaim (ftype (function (list symbol) (values list list))
-               extract-flet-variables))
-(defun extract-flet-variables (definitions context)
-  (collect ((names)
-           (defs))
-    (dolist (def definitions)
-      (when (or (atom def) (< (length def) 2))
-       (compiler-error "The ~S definition spec ~S is malformed." context def))
-
-      (let ((name (check-function-name (first def))))
-       (names name)
-       (multiple-value-bind (forms decls) (sb!sys:parse-body (cddr def))
-         (defs `(lambda ,(second def)
-                  ,@decls
-                  (block ,(function-name-block-name name)
-                    . ,forms))))))
-    (values (names) (defs))))
-
-(def-ir1-translator flet ((definitions &body body)
-                         start cont)
-  #!+sb-doc
-  "FLET ({(Name Lambda-List Declaration* Form*)}*) Declaration* Body-Form*
-  Evaluate the Body-Forms with some local function definitions. The bindings
-  do not enclose the definitions; any use of Name in the Forms will refer to
-  the lexically apparent function definition in the enclosing environment."
-  (multiple-value-bind (forms decls) (sb!sys:parse-body body nil)
-    (multiple-value-bind (names defs)
-       (extract-flet-variables definitions 'flet)
-      (let* ((fvars (mapcar (lambda (n d)
-                             (ir1-convert-lambda d n))
-                           names defs))
-            (*lexenv* (make-lexenv
-                       :default (process-decls decls nil fvars cont)
-                       :functions (pairlis names fvars))))
-       (ir1-convert-progn-body start cont forms)))))
-
-;;; For LABELS, we have to create dummy function vars and add them to
-;;; the function namespace while converting the functions. We then
-;;; modify all the references to these leaves so that they point to
-;;; the real functional leaves. We also backpatch the FENV so that if
-;;; the lexical environment is used for inline expansion we will get
-;;; the right functions.
-(def-ir1-translator labels ((definitions &body body) start cont)
-  #!+sb-doc
-  "LABELS ({(Name Lambda-List Declaration* Form*)}*) Declaration* Body-Form*
-  Evaluate the Body-Forms with some local function definitions. The bindings
-  enclose the new definitions, so the defined functions can call themselves or
-  each other."
-  (multiple-value-bind (forms decls) (sb!sys:parse-body body nil)
-    (multiple-value-bind (names defs)
-       (extract-flet-variables definitions 'labels)
-      (let* ((new-fenv (loop for name in names
-                            collect (cons name (make-functional :name name))))
-            (real-funs
-             (let ((*lexenv* (make-lexenv :functions new-fenv)))
-               (mapcar (lambda (n d)
-                         (ir1-convert-lambda d n))
-                       names defs))))
-
-       (loop for real in real-funs and env in new-fenv do
-             (let ((dum (cdr env)))
-               (substitute-leaf real dum)
-               (setf (cdr env) real)))
-
-       (let ((*lexenv* (make-lexenv
-                        :default (process-decls decls nil real-funs cont)
-                        :functions (pairlis names real-funs))))
-         (ir1-convert-progn-body start cont forms))))))
-\f
-;;;; THE
-
-;;; Do stuff to recognize a THE or VALUES declaration. CONT is the
-;;; continuation that the assertion applies to, TYPE is the type
-;;; specifier and Lexenv is the current lexical environment. NAME is
-;;; the name of the declaration we are doing, for use in error
-;;; messages.
-;;;
-;;; This is somewhat involved, since a type assertion may only be made
-;;; on a continuation, not on a node. We can't just set the
-;;; continuation asserted type and let it go at that, since there may
-;;; be parallel THE's for the same continuation, i.e.:
-;;;     (if ...
-;;;     (the foo ...)
-;;;     (the bar ...))
-;;;
-;;; In this case, our representation can do no better than the union
-;;; of these assertions. And if there is a branch with no assertion,
-;;; we have nothing at all. We really need to recognize scoping, since
-;;; we need to be able to discern between parallel assertions (which
-;;; we union) and nested ones (which we intersect).
-;;;
-;;; We represent the scoping by throwing our innermost (intersected)
-;;; assertion on CONT into the TYPE-RESTRICTIONS. As we go down, we
-;;; intersect our assertions together. If CONT has no uses yet, we
-;;; have not yet bottomed out on the first COND branch; in this case
-;;; we optimistically assume that this type will be the one we end up
-;;; with, and set the ASSERTED-TYPE to it. We can never get better
-;;; than the type that we have the first time we bottom out. Later
-;;; THE's (or the absence thereof) can only weaken this result.
-;;;
-;;; We make this work by getting USE-CONTINUATION to do the unioning
-;;; across COND branches. We can't do it here, since we don't know how
-;;; many branches there are going to be.
-(defun do-the-stuff (type cont lexenv name)
-  (declare (type continuation cont) (type lexenv lexenv))
-  (let* ((ctype (values-specifier-type type))
-        (old-type (or (lexenv-find cont type-restrictions)
-                      *wild-type*))
-        (intersects (values-types-equal-or-intersect old-type ctype))
-        (int (values-type-intersection old-type ctype))
-        (new (if intersects int old-type)))
-    (when (null (find-uses cont))
-      (setf (continuation-asserted-type cont) new))
-    (when (and (not intersects)
-              (not (policy *lexenv*
-                           (= inhibit-warnings 3)))) ;FIXME: really OK to suppress?
-      (compiler-warning
-       "The type ~S in ~S declaration conflicts with an enclosing assertion:~%   ~S"
-       (type-specifier ctype)
-       name
-       (type-specifier old-type)))
-    (make-lexenv :type-restrictions `((,cont . ,new))
-                :default lexenv)))
-
-;;; Assert that FORM evaluates to the specified type (which may be a
-;;; VALUES type).
-;;;
-;;; FIXME: In a version of CMU CL that I used at Cadabra ca. 20000101,
-;;; this didn't seem to expand into an assertion, at least for ALIEN
-;;; values. Check that SBCL doesn't have this problem.
-(def-ir1-translator the ((type value) start cont)
-  (let ((*lexenv* (do-the-stuff type cont *lexenv* 'the)))
-    (ir1-convert start cont value)))
-
-;;; This is like the THE special form, except that it believes
-;;; whatever you tell it. It will never generate a type check, but
-;;; will cause a warning if the compiler can prove the assertion is
-;;; wrong.
-;;;
-;;; Since the CONTINUATION-DERIVED-TYPE is computed as the union of
-;;; its uses's types, setting it won't work. Instead we must intersect
-;;; the type with the uses's DERIVED-TYPE.
-(def-ir1-translator truly-the ((type value) start cont)
-  #!+sb-doc
-  (declare (inline member))
-  (let ((type (values-specifier-type type))
-       (old (find-uses cont)))
-    (ir1-convert start cont value)
-    (do-uses (use cont)
-      (unless (member use old :test #'eq)
-       (derive-node-type use type)))))
-\f
-;;;; SETQ
-
-;;; If there is a definition in LEXENV-VARIABLES, just set that,
-;;; otherwise look at the global information. If the name is for a
-;;; constant, then error out.
-(def-ir1-translator setq ((&whole source &rest things) start cont)
-  (let ((len (length things)))
-    (when (oddp len)
-      (compiler-error "odd number of args to SETQ: ~S" source))
-    (if (= len 2)
-       (let* ((name (first things))
-              (leaf (or (lexenv-find name variables)
-                        (find-free-variable name))))
-         (etypecase leaf
-           (leaf
-            (when (or (constant-p leaf)
-                      (and (global-var-p leaf)
-                           (eq (global-var-kind leaf) :constant)))
-              (compiler-error "~S is a constant and thus can't be set." name))
-            (when (and (lambda-var-p leaf)
-                       (lambda-var-ignorep leaf))
-              ;; ANSI's definition of "Declaration IGNORE, IGNORABLE"
-              ;; requires that this be a STYLE-WARNING, not a full warning.
-              (compiler-style-warning
-               "~S is being set even though it was declared to be ignored."
-               name))
-            (set-variable start cont leaf (second things)))
-           (cons
-            (aver (eq (car leaf) 'MACRO))
-            (ir1-convert start cont `(setf ,(cdr leaf) ,(second things))))
-           (heap-alien-info
-            (ir1-convert start cont
-                         `(%set-heap-alien ',leaf ,(second things))))))
-       (collect ((sets))
-         (do ((thing things (cddr thing)))
-             ((endp thing)
-              (ir1-convert-progn-body start cont (sets)))
-           (sets `(setq ,(first thing) ,(second thing))))))))
-
-;;; This is kind of like REFERENCE-LEAF, but we generate a SET node.
-;;; This should only need to be called in SETQ.
-(defun set-variable (start cont var value)
-  (declare (type continuation start cont) (type basic-var var))
-  (let ((dest (make-continuation)))
-    (setf (continuation-asserted-type dest) (leaf-type var))
-    (ir1-convert start dest value)
-    (let ((res (make-set :var var :value dest)))
-      (setf (continuation-dest dest) res)
-      (setf (leaf-ever-used var) t)
-      (push res (basic-var-sets var))
-      (prev-link res dest)
-      (use-continuation res cont))))
-\f
-;;;; CATCH, THROW and UNWIND-PROTECT
-
-;;; We turn THROW into a multiple-value-call of a magical function,
-;;; since as as far as IR1 is concerned, it has no interesting
-;;; properties other than receiving multiple-values.
-(def-ir1-translator throw ((tag result) start cont)
-  #!+sb-doc
-  "Throw Tag Form
-  Do a non-local exit, return the values of Form from the CATCH whose tag
-  evaluates to the same thing as Tag."
-  (ir1-convert start cont
-              `(multiple-value-call #'%throw ,tag ,result)))
-
-;;; This is a special special form used to instantiate a cleanup as
-;;; the current cleanup within the body. KIND is a the kind of cleanup
-;;; to make, and MESS-UP is a form that does the mess-up action. We
-;;; make the MESS-UP be the USE of the MESS-UP form's continuation,
-;;; and introduce the cleanup into the lexical environment. We
-;;; back-patch the ENTRY-CLEANUP for the current cleanup to be the new
-;;; cleanup, since this inner cleanup is the interesting one.
-(def-ir1-translator %within-cleanup ((kind mess-up &body body) start cont)
-  (let ((dummy (make-continuation))
-       (dummy2 (make-continuation)))
-    (ir1-convert start dummy mess-up)
-    (let* ((mess-node (continuation-use dummy))
-          (cleanup (make-cleanup :kind kind
-                                 :mess-up mess-node))
-          (old-cup (lexenv-cleanup *lexenv*))
-          (*lexenv* (make-lexenv :cleanup cleanup)))
-      (setf (entry-cleanup (cleanup-mess-up old-cup)) cleanup)
-      (ir1-convert dummy dummy2 '(%cleanup-point))
-      (ir1-convert-progn-body dummy2 cont body))))
-
-;;; This is a special special form that makes an "escape function"
-;;; which returns unknown values from named block. We convert the
-;;; function, set its kind to :ESCAPE, and then reference it. The
-;;; :Escape kind indicates that this function's purpose is to
-;;; represent a non-local control transfer, and that it might not
-;;; actually have to be compiled.
-;;;
-;;; Note that environment analysis replaces references to escape
-;;; functions with references to the corresponding NLX-INFO structure.
-(def-ir1-translator %escape-function ((tag) start cont)
-  (let ((fun (ir1-convert-lambda
-             `(lambda ()
-                (return-from ,tag (%unknown-values))))))
-    (setf (functional-kind fun) :escape)
-    (reference-leaf start cont fun)))
-
-;;; Yet another special special form. This one looks up a local
-;;; function and smashes it to a :CLEANUP function, as well as
-;;; referencing it.
-(def-ir1-translator %cleanup-function ((name) start cont)
-  (let ((fun (lexenv-find name functions)))
-    (aver (lambda-p fun))
-    (setf (functional-kind fun) :cleanup)
-    (reference-leaf start cont fun)))
-
-;;; We represent the possibility of the control transfer by making an
-;;; "escape function" that does a lexical exit, and instantiate the
-;;; cleanup using %WITHIN-CLEANUP.
-(def-ir1-translator catch ((tag &body body) start cont)
-  #!+sb-doc
-  "Catch Tag Form*
-  Evaluates Tag and instantiates it as a catcher while the body forms are
-  evaluated in an implicit PROGN. If a THROW is done to Tag within the dynamic
-  scope of the body, then control will be transferred to the end of the body
-  and the thrown values will be returned."
-  (ir1-convert
-   start cont
-   (let ((exit-block (gensym "EXIT-BLOCK-")))
-     `(block ,exit-block
-       (%within-cleanup
-           :catch
-           (%catch (%escape-function ,exit-block) ,tag)
-         ,@body)))))
-
-;;; UNWIND-PROTECT is similar to CATCH, but more hairy. We make the
-;;; cleanup forms into a local function so that they can be referenced
-;;; both in the case where we are unwound and in any local exits. We
-;;; use %CLEANUP-FUNCTION on this to indicate that reference by
-;;; %UNWIND-PROTECT ISN'T "real", and thus doesn't cause creation of
-;;; an XEP.
-(def-ir1-translator unwind-protect ((protected &body cleanup) start cont)
-  #!+sb-doc
-  "Unwind-Protect Protected Cleanup*
-  Evaluate the form Protected, returning its values. The cleanup forms are
-  evaluated whenever the dynamic scope of the Protected form is exited (either
-  due to normal completion or a non-local exit such as THROW)."
-  (ir1-convert
-   start cont
-   (let ((cleanup-fun (gensym "CLEANUP-FUN-"))
-        (drop-thru-tag (gensym "DROP-THRU-TAG-"))
-        (exit-tag (gensym "EXIT-TAG-"))
-        (next (gensym "NEXT"))
-        (start (gensym "START"))
-        (count (gensym "COUNT")))
-     `(flet ((,cleanup-fun () ,@cleanup nil))
-       ;; FIXME: If we ever get DYNAMIC-EXTENT working, then
-       ;; ,CLEANUP-FUN should probably be declared DYNAMIC-EXTENT,
-       ;; and something can be done to make %ESCAPE-FUNCTION have
-       ;; dynamic extent too.
-       (block ,drop-thru-tag
-         (multiple-value-bind (,next ,start ,count)
-             (block ,exit-tag
-               (%within-cleanup
-                   :unwind-protect
-                   (%unwind-protect (%escape-function ,exit-tag)
-                                    (%cleanup-function ,cleanup-fun))
-                 (return-from ,drop-thru-tag ,protected)))
-           (,cleanup-fun)
-           (%continue-unwind ,next ,start ,count)))))))
-\f
-;;;; multiple-value stuff
-
-;;; If there are arguments, MULTIPLE-VALUE-CALL turns into an
-;;; MV-COMBINATION.
-;;;
-;;; If there are no arguments, then we convert to a normal
-;;; combination, ensuring that a MV-COMBINATION always has at least
-;;; one argument. This can be regarded as an optimization, but it is
-;;; more important for simplifying compilation of MV-COMBINATIONS.
-(def-ir1-translator multiple-value-call ((fun &rest args) start cont)
-  #!+sb-doc
-  "MULTIPLE-VALUE-CALL Function Values-Form*
-  Call Function, passing all the values of each Values-Form as arguments,
-  values from the first Values-Form making up the first argument, etc."
-  (let* ((fun-cont (make-continuation))
-        (node (if args
-                  (make-mv-combination fun-cont)
-                  (make-combination fun-cont))))
-    (ir1-convert start fun-cont
-                (if (and (consp fun) (eq (car fun) 'function))
-                    fun
-                    `(%coerce-callable-to-function ,fun)))
-    (setf (continuation-dest fun-cont) node)
-    (assert-continuation-type fun-cont
-                             (specifier-type '(or function symbol)))
-    (collect ((arg-conts))
-      (let ((this-start fun-cont))
-       (dolist (arg args)
-         (let ((this-cont (make-continuation node)))
-           (ir1-convert this-start this-cont arg)
-           (setq this-start this-cont)
-           (arg-conts this-cont)))
-       (prev-link node this-start)
-       (use-continuation node cont)
-       (setf (basic-combination-args node) (arg-conts))))))
-
-;;; MULTIPLE-VALUE-PROG1 is represented implicitly in IR1 by having a
-;;; the result code use result continuation (CONT), but transfer
-;;; control to the evaluation of the body. In other words, the result
-;;; continuation isn't IMMEDIATELY-USED-P by the nodes that compute
-;;; the result.
-;;;
-;;; In order to get the control flow right, we convert the result with
-;;; a dummy result continuation, then convert all the uses of the
-;;; dummy to be uses of CONT. If a use is an EXIT, then we also
-;;; substitute CONT for the dummy in the corresponding ENTRY node so
-;;; that they are consistent. Note that this doesn't amount to
-;;; changing the exit target, since the control destination of an exit
-;;; is determined by the block successor; we are just indicating the
-;;; continuation that the result is delivered to.
-;;;
-;;; We then convert the body, using another dummy continuation in its
-;;; own block as the result. After we are done converting the body, we
-;;; move all predecessors of the dummy end block to CONT's block.
-;;;
-;;; Note that we both exploit and maintain the invariant that the CONT
-;;; to an IR1 convert method either has no block or starts the block
-;;; that control should transfer to after completion for the form.
-;;; Nested MV-PROG1's work because during conversion of the result
-;;; form, we use dummy continuation whose block is the true control
-;;; destination.
-(def-ir1-translator multiple-value-prog1 ((result &rest forms) start cont)
-  #!+sb-doc
-  "MULTIPLE-VALUE-PROG1 Values-Form Form*
-  Evaluate Values-Form and then the Forms, but return all the values of
-  Values-Form."
-  (continuation-starts-block cont)
-  (let* ((dummy-result (make-continuation))
-        (dummy-start (make-continuation))
-        (cont-block (continuation-block cont)))
-    (continuation-starts-block dummy-start)
-    (ir1-convert start dummy-start result)
-
-    (substitute-continuation-uses cont dummy-start)
-
-    (continuation-starts-block dummy-result)
-    (ir1-convert-progn-body dummy-start dummy-result forms)
-    (let ((end-block (continuation-block dummy-result)))
-      (dolist (pred (block-pred end-block))
-       (unlink-blocks pred end-block)
-       (link-blocks pred cont-block))
-      (aver (not (continuation-dest dummy-result)))
-      (delete-continuation dummy-result)
-      (remove-from-dfo end-block))))
-\f
-;;;; interface to defining macros
-
-;;;; FIXME:
-;;;;   classic CMU CL comment:
-;;;;     DEFMACRO and DEFUN expand into calls to %DEFxxx functions
-;;;;     so that we get a chance to see what is going on. We define
-;;;;     IR1 translators for these functions which look at the
-;;;;     definition and then generate a call to the %%DEFxxx function.
-;;;; Alas, this implementation doesn't do the right thing for
-;;;; non-toplevel uses of these forms, so this should probably
-;;;; be changed to use EVAL-WHEN instead.
-
-;;; Return a new source path with any stuff intervening between the
-;;; current path and the first form beginning with NAME stripped off.
-;;; This is used to hide the guts of DEFmumble macros to prevent
-;;; annoying error messages.
-(defun revert-source-path (name)
-  (do ((path *current-path* (cdr path)))
-      ((null path) *current-path*)
-    (let ((first (first path)))
-      (when (or (eq first name)
-               (eq first 'original-source-start))
-       (return path)))))
-
-;;; Warn about incompatible or illegal definitions and add the macro
-;;; to the compiler environment.
-;;;
-;;; Someday we could check for macro arguments being incompatibly
-;;; redefined. Doing this right will involve finding the old macro
-;;; lambda-list and comparing it with the new one.
-(def-ir1-translator %defmacro ((qname qdef lambda-list doc) start cont
-                              :kind :function)
-  (let (;; QNAME is typically a quoted name. I think the idea is to
-       ;; let %DEFMACRO work as an ordinary function when
-       ;; interpreting. Whatever the reason the quote is there, we
-       ;; don't want it any more. -- WHN 19990603
-       (name (eval qname))
-       ;; QDEF should be a sharp-quoted definition. We don't want to
-       ;; make a function of it just yet, so we just drop the
-       ;; sharp-quote.
-       (def (progn
-              (aver (eq 'function (first qdef)))
-              (aver (proper-list-of-length-p qdef 2))
-              (second qdef))))
-
-    (/show "doing IR1 translator for %DEFMACRO" name)
-
-    (unless (symbolp name)
-      (compiler-error "The macro name ~S is not a symbol." name))
-
-    (ecase (info :function :kind name)
-      ((nil))
-      (:function
-       (remhash name *free-functions*)
-       (undefine-function-name name)
-       (compiler-warning
-       "~S is being redefined as a macro when it was ~
-         previously ~(~A~) to be a function."
-       name
-       (info :function :where-from name)))
-      (:macro)
-      (:special-form
-       (compiler-error "The special form ~S can't be redefined as a macro."
-                      name)))
-
-    (setf (info :function :kind name) :macro
-         (info :function :where-from name) :defined
-         (info :function :macro-function name) (coerce def 'function))
-
-    (let* ((*current-path* (revert-source-path 'defmacro))
-          (fun (ir1-convert-lambda def name)))
-      (setf (leaf-name fun)
-           (concatenate 'string "DEFMACRO " (symbol-name name)))
-      (setf (functional-arg-documentation fun) (eval lambda-list))
-
-      (ir1-convert start cont `(%%defmacro ',name ,fun ,doc)))
-
-    (when sb!xc:*compile-print*
-      ;; FIXME: It would be nice to convert this, and the other places
-      ;; which create compiler diagnostic output prefixed by
-      ;; semicolons, to use some common utility which automatically
-      ;; prefixes all its output with semicolons. (The addition of
-      ;; semicolon prefixes was introduced ca. sbcl-0.6.8.10 as the
-      ;; "MNA compiler message patch", and implemented by modifying a
-      ;; bunch of output statements on a case-by-case basis, which
-      ;; seems unnecessarily error-prone and unclear, scattering
-      ;; implicit information about output style throughout the
-      ;; system.) Starting by rewriting COMPILER-MUMBLE to add
-      ;; semicolon prefixes would be a good start, and perhaps also:
-      ;;   * Add semicolon prefixes for "FOO assembled" messages emitted 
-      ;;     when e.g. src/assembly/x86/assem-rtns.lisp is processed.
-      ;;   * At least some debugger output messages deserve semicolon
-      ;;     prefixes too:
-      ;;     ** restarts table
-      ;;     ** "Within the debugger, you can type HELP for help."
-      (compiler-mumble "~&; converted ~S~%" name))))
-
-(def-ir1-translator %define-compiler-macro ((name def lambda-list doc)
-                                           start cont
-                                           :kind :function)
-  (let ((name (eval name))
-       (def (second def))) ; We don't want to make a function just yet...
-
-    (when (eq (info :function :kind name) :special-form)
-      (compiler-error "attempt to define a compiler-macro for special form ~S"
-                     name))
-
-    (setf (info :function :compiler-macro-function name)
-         (coerce def 'function))
-
-    (let* ((*current-path* (revert-source-path 'define-compiler-macro))
-          (fun (ir1-convert-lambda def name)))
-      (setf (leaf-name fun)
-           (let ((*print-case* :upcase))
-             (format nil "DEFINE-COMPILER-MACRO ~S" name)))
-      (setf (functional-arg-documentation fun) (eval lambda-list))
-
-      (ir1-convert start cont `(%%define-compiler-macro ',name ,fun ,doc)))
-
-    (when sb!xc:*compile-print*
-      (compiler-mumble "~&; converted ~S~%" name))))
-\f
 ;;;; defining global functions
 
 ;;; Convert FUN as a lambda in the null environment, but use the
                "previous definition"))))
 
 ;;; Convert a lambda doing all the basic stuff we would do if we were
-;;; converting a DEFUN. This is used both by the %DEFUN translator and
-;;; for global inline expansion.
+;;; converting a DEFUN. In the old CMU CL system, this was used both
+;;; by the %DEFUN translator and for global inline expansion, but
+;;; since sbcl-0.pre7.something %DEFUN does things differently.
+;;; FIXME: And now it's probably worth rethinking whether this
+;;; function is a good idea.
 ;;;
 ;;; Unless a :INLINE function, we temporarily clobber the inline
 ;;; expansion. This prevents recursive inline expansion of
index 2832443..31f8748 100644 (file)
           nil)
          (t t))))
 \f
-;;;; compiler error context determination
-
-(declaim (special *current-path*))
-
-;;; We bind print level and length when printing out messages so that
-;;; we don't dump huge amounts of garbage.
-;;;
-;;; FIXME: It's not possible to get the defaults right for everyone.
-;;; So: Should these variables be in the SB-EXT package? Or should we
-;;; just get rid of them completely and just use the bare
-;;; CL:*PRINT-FOO* variables instead?
-(declaim (type (or unsigned-byte null)
-              *compiler-error-print-level*
-              *compiler-error-print-length*
-              *compiler-error-print-lines*))
-(defvar *compiler-error-print-level* 5
-  #!+sb-doc
-  "the value for *PRINT-LEVEL* when printing compiler error messages")
-(defvar *compiler-error-print-length* 10
-  #!+sb-doc
-  "the value for *PRINT-LENGTH* when printing compiler error messages")
-(defvar *compiler-error-print-lines* 12
-  #!+sb-doc
-  "the value for *PRINT-LINES* when printing compiler error messages")
-
-(defvar *enclosing-source-cutoff* 1
-  #!+sb-doc
-  "The maximum number of enclosing non-original source forms (i.e. from
-  macroexpansion) that we print in full. For additional enclosing forms, we
-  print only the CAR.")
-(declaim (type unsigned-byte *enclosing-source-cutoff*))
-
-;;; We separate the determination of compiler error contexts from the
-;;; actual signalling of those errors by objectifying the error
-;;; context. This allows postponement of the determination of how (and
-;;; if) to signal the error.
-;;;
-;;; We take care not to reference any of the IR1 so that pending
-;;; potential error messages won't prevent the IR1 from being GC'd. To
-;;; this end, we convert source forms to strings so that source forms
-;;; that contain IR1 references (e.g. %DEFUN) don't hold onto the IR.
-(defstruct (compiler-error-context
-           #-no-ansi-print-object
-           (:print-object (lambda (x stream)
-                            (print-unreadable-object (x stream :type t))))
-           (:copier nil))
-  ;; a list of the stringified CARs of the enclosing non-original source forms
-  ;; exceeding the *enclosing-source-cutoff*
-  (enclosing-source nil :type list)
-  ;; a list of stringified enclosing non-original source forms
-  (source nil :type list)
-  ;; the stringified form in the original source that expanded into SOURCE
-  (original-source (required-argument) :type simple-string)
-  ;; a list of prefixes of "interesting" forms that enclose original-source
-  (context nil :type list)
-  ;; the FILE-INFO-NAME for the relevant FILE-INFO
-  (file-name (required-argument)
-            :type (or pathname (member :lisp :stream)))
-  ;; the file position at which the top-level form starts, if applicable
-  (file-position nil :type (or index null))
-  ;; the original source part of the source path
-  (original-source-path nil :type list))
-
-;;; If true, this is the node which is used as context in compiler warning
-;;; messages.
-(declaim (type (or null compiler-error-context node) *compiler-error-context*))
-(defvar *compiler-error-context* nil)
-
-;;; a hashtable mapping macro names to source context parsers. Each parser
-;;; function returns the source-context list for that form.
-(defvar *source-context-methods* (make-hash-table))
-
-;;; documentation originally from cmu-user.tex:
-;;;   This macro defines how to extract an abbreviated source context from
-;;;   the \var{name}d form when it appears in the compiler input.
-;;;   \var{lambda-list} is a \code{defmacro} style lambda-list used to
-;;;   parse the arguments. The \var{body} should return a list of
-;;;   subforms that can be printed on about one line. There are
-;;;   predefined methods for \code{defstruct}, \code{defmethod}, etc. If
-;;;   no method is defined, then the first two subforms are returned.
-;;;   Note that this facility implicitly determines the string name
-;;;   associated with anonymous functions.
-;;; So even though SBCL itself only uses this macro within this file,
-;;; it's a reasonable thing to put in SB-EXT in case some dedicated
-;;; user wants to do some heavy tweaking to make SBCL give more
-;;; informative output about his code.
-(defmacro def-source-context (name lambda-list &body body)
-  #!+sb-doc
-  "DEF-SOURCE-CONTEXT Name Lambda-List Form*
-   This macro defines how to extract an abbreviated source context from the
-   Named form when it appears in the compiler input. Lambda-List is a DEFMACRO
-   style lambda-list used to parse the arguments. The Body should return a
-   list of subforms suitable for a \"~{~S ~}\" format string."
-  (let ((n-whole (gensym)))
-    `(setf (gethash ',name *source-context-methods*)
-          #'(lambda (,n-whole)
-              (destructuring-bind ,lambda-list ,n-whole ,@body)))))
-
-(def-source-context defstruct (name-or-options &rest slots)
-  (declare (ignore slots))
-  `(defstruct ,(if (consp name-or-options)
-                  (car name-or-options)
-                  name-or-options)))
-
-(def-source-context function (thing)
-  (if (and (consp thing) (eq (first thing) 'lambda) (consp (rest thing)))
-      `(lambda ,(second thing))
-      `(function ,thing)))
-
-;;; Return the first two elements of FORM if FORM is a list. Take the
-;;; CAR of the second form if appropriate.
-(defun source-form-context (form)
-  (cond ((atom form) nil)
-       ((>= (length form) 2)
-        (funcall (gethash (first form) *source-context-methods*
-                          #'(lambda (x)
-                              (declare (ignore x))
-                              (list (first form) (second form))))
-                 (rest form)))
-       (t
-        form)))
-
-;;; Given a source path, return the original source form and a
-;;; description of the interesting aspects of the context in which it
-;;; appeared. The context is a list of lists, one sublist per context
-;;; form. The sublist is a list of some of the initial subforms of the
-;;; context form.
-;;;
-;;; For now, we use the first two subforms of each interesting form. A
-;;; form is interesting if the first element is a symbol beginning
-;;; with "DEF" and it is not the source form. If there is no
-;;; DEF-mumble, then we use the outermost containing form. If the
-;;; second subform is a list, then in some cases we return the CAR of
-;;; that form rather than the whole form (i.e. don't show DEFSTRUCT
-;;; options, etc.)
-(defun find-original-source (path)
-  (declare (list path))
-  (let* ((rpath (reverse (source-path-original-source path)))
-        (tlf (first rpath))
-        (root (find-source-root tlf *source-info*)))
-    (collect ((context))
-      (let ((form root)
-           (current (rest rpath)))
-       (loop
-         (when (atom form)
-           (aver (null current))
-           (return))
-         (let ((head (first form)))
-           (when (symbolp head)
-             (let ((name (symbol-name head)))
-               (when (and (>= (length name) 3) (string= name "DEF" :end1 3))
-                 (context (source-form-context form))))))
-         (when (null current) (return))
-         (setq form (nth (pop current) form)))
-       
-       (cond ((context)
-              (values form (context)))
-             ((and path root)
-              (let ((c (source-form-context root)))
-                (values form (if c (list c) nil))))
-             (t
-              (values '(unable to locate source)
-                      '((some strange place)))))))))
-
-;;; Convert a source form to a string, suitably formatted for use in
-;;; compiler warnings.
-(defun stringify-form (form &optional (pretty t))
-  (let ((*print-level* *compiler-error-print-level*)
-       (*print-length* *compiler-error-print-length*)
-       (*print-lines* *compiler-error-print-lines*)
-       (*print-pretty* pretty))
-    (if pretty
-       (format nil "~<~@;  ~S~:>" (list form))
-       (prin1-to-string form))))
-
-;;; Return a COMPILER-ERROR-CONTEXT structure describing the current
-;;; error context, or NIL if we can't figure anything out. ARGS is a
-;;; list of things that are going to be printed out in the error
-;;; message, and can thus be blown off when they appear in the source
-;;; context.
-(defun find-error-context (args)
-  (let ((context *compiler-error-context*))
-    (if (compiler-error-context-p context)
-       context
-       (let ((path (or (and (boundp '*current-path*) *current-path*)
-                       (if context
-                           (node-source-path context)
-                           nil))))
-         (when (and *source-info* path)
-           (multiple-value-bind (form src-context) (find-original-source path)
-             (collect ((full nil cons)
-                       (short nil cons))
-               (let ((forms (source-path-forms path))
-                     (n 0))
-                 (dolist (src (if (member (first forms) args)
-                                  (rest forms)
-                                  forms))
-                   (if (>= n *enclosing-source-cutoff*)
-                       (short (stringify-form (if (consp src)
-                                                  (car src)
-                                                  src)
-                                              nil))
-                       (full (stringify-form src)))
-                   (incf n)))
-
-               (let* ((tlf (source-path-tlf-number path))
-                      (file-info (source-info-file-info *source-info*)))
-                 (make-compiler-error-context
-                  :enclosing-source (short)
-                  :source (full)
-                  :original-source (stringify-form form)
-                  :context src-context
-                  :file-name (file-info-name file-info)
-                  :file-position
-                  (multiple-value-bind (ignore pos)
-                      (find-source-root tlf *source-info*)
-                    (declare (ignore ignore))
-                    pos)
-                  :original-source-path
-                  (source-path-original-source path))))))))))
-\f
-;;;; printing error messages
-
-;;; We save the context information that we printed out most recently
-;;; so that we don't print it out redundantly.
-
-;;; The last COMPILER-ERROR-CONTEXT that we printed.
-(defvar *last-error-context* nil)
-(declaim (type (or compiler-error-context null) *last-error-context*))
-
-;;; The format string and args for the last error we printed.
-(defvar *last-format-string* nil)
-(defvar *last-format-args* nil)
-(declaim (type (or string null) *last-format-string*))
-(declaim (type list *last-format-args*))
-
-;;; The number of times that the last error message has been emitted,
-;;; so that we can compress duplicate error messages.
-(defvar *last-message-count* 0)
-(declaim (type index *last-message-count*))
-
-;;; If the last message was given more than once, then print out an
-;;; indication of how many times it was repeated. We reset the message
-;;; count when we are done.
-(defun note-message-repeats (&optional (terpri t))
-  (cond ((= *last-message-count* 1)
-        (when terpri (terpri *error-output*)))
-       ((> *last-message-count* 1)
-          (format *error-output* "~&; [Last message occurs ~D times.]~2%"
-                *last-message-count*)))
-  (setq *last-message-count* 0))
-
-;;; Print out the message, with appropriate context if we can find it.
-;;; If the context is different from the context of the last message
-;;; we printed, then we print the context. If the original source is
-;;; different from the source we are working on, then we print the
-;;; current source in addition to the original source.
-;;;
-;;; We suppress printing of messages identical to the previous, but
-;;; record the number of times that the message is repeated.
-(defun print-compiler-message (format-string format-args)
-
-  (declare (type simple-string format-string))
-  (declare (type list format-args))
-  
-  (let ((stream *error-output*)
-       (context (find-error-context format-args)))
-    (cond
-     (context
-      (let ((file (compiler-error-context-file-name context))
-           (in (compiler-error-context-context context))
-           (form (compiler-error-context-original-source context))
-           (enclosing (compiler-error-context-enclosing-source context))
-           (source (compiler-error-context-source context))
-           (last *last-error-context*))
-
-       (unless (and last
-                    (equal file (compiler-error-context-file-name last)))
-         (when (pathnamep file)
-           (note-message-repeats)
-           (setq last nil)
-            (format stream "~2&; file: ~A~%" (namestring file))))
-
-       (unless (and last
-                    (equal in (compiler-error-context-context last)))
-         (note-message-repeats)
-         (setq last nil)
-          (format stream "~&")
-          (pprint-logical-block (stream nil :per-line-prefix "; ")
-            (format stream "in:~{~<~%    ~4:;~{ ~S~}~>~^ =>~}" in))
-          (format stream "~%"))
-
-
-       (unless (and last
-                    (string= form
-                             (compiler-error-context-original-source last)))
-         (note-message-repeats)
-         (setq last nil)
-          (format stream "~&")
-          (pprint-logical-block (stream nil :per-line-prefix "; ")
-            (format stream "  ~A" form))
-          (format stream "~&"))
-
-       (unless (and last
-                    (equal enclosing
-                           (compiler-error-context-enclosing-source last)))
-         (when enclosing
-           (note-message-repeats)
-           (setq last nil)
-           (format stream "~&; --> ~{~<~%; --> ~1:;~A~> ~}~%" enclosing)))
-
-       (unless (and last
-                    (equal source (compiler-error-context-source last)))
-         (setq *last-format-string* nil)
-         (when source
-           (note-message-repeats)
-           (dolist (src source)
-              (format stream "~&")
-              (write-string "; ==>" stream)
-              (format stream "~&")
-              (pprint-logical-block (stream nil :per-line-prefix "; ")
-                (write-string src stream)))))))
-     (t
-       (format stream "~&")
-      (note-message-repeats)
-      (setq *last-format-string* nil)
-       (format stream "~&")))
-
-    (setq *last-error-context* context)
-
-    (unless (and (equal format-string *last-format-string*)
-                (tree-equal format-args *last-format-args*))
-      (note-message-repeats nil)
-      (setq *last-format-string* format-string)
-      (setq *last-format-args* format-args)
-      (let ((*print-level*  *compiler-error-print-level*)
-           (*print-length* *compiler-error-print-length*)
-           (*print-lines*  *compiler-error-print-lines*))
-        (format stream "~&")
-        (pprint-logical-block (stream nil :per-line-prefix "; ")
-          (format stream "~&~?" format-string format-args))
-        (format stream "~&"))))
-
-  (incf *last-message-count*)
-  (values))
-
-(defun print-compiler-condition (condition)
-  (declare (type condition condition))
-  (let (;; These different classes of conditions have different
-       ;; effects on the return codes of COMPILE-FILE, so it's nice
-       ;; for users to be able to pick them out by lexical search
-       ;; through the output.
-       (what (etypecase condition
-               (style-warning 'style-warning)
-               (warning 'warning)
-               (error 'error))))
-    (multiple-value-bind (format-string format-args)
-       (if (typep condition 'simple-condition)
-           (values (simple-condition-format-control condition)
-                   (simple-condition-format-arguments condition))
-           (values "~A"
-                   (list (with-output-to-string (s)
-                           (princ condition s)))))
-      (print-compiler-message (format nil
-                                     "caught ~S:~%  ~A"
-                                     what
-                                     format-string)
-                             format-args)))
-  (values))
-
-;;; COMPILER-NOTE is vaguely like COMPILER-ERROR and the other
-;;; condition-signalling functions, but it just writes some output
-;;; instead of signalling. (In CMU CL, it did signal a condition, but
-;;; this didn't seem to work all that well; it was weird to have
-;;; COMPILE-FILE return with WARNINGS-P set when the only problem was
-;;; that the compiler couldn't figure out how to compile something as
-;;; efficiently as it liked.)
-(defun compiler-note (format-string &rest format-args)
-  (unless (if *compiler-error-context*
-             (policy *compiler-error-context* (= inhibit-warnings 3))
-             (policy *lexenv* (= inhibit-warnings 3)))
-    (incf *compiler-note-count*)
-    (print-compiler-message (format nil "note: ~A" format-string)
-                           format-args))
-  (values))
-
-;;; Issue a note when we might or might not be in the compiler.
-(defun maybe-compiler-note (&rest rest)
-  (if (boundp '*lexenv*) ; if we're in the compiler
-      (apply #'compiler-note rest)
-      (let ((stream *error-output*))
-       (pprint-logical-block (stream nil :per-line-prefix ";")
-         
-         (format stream " note: ~3I~_")
-         (pprint-logical-block (stream nil)
-           (apply #'format stream rest)))
-       (fresh-line stream)))) ; (outside logical block, no per-line-prefix)
-
-;;; The politically correct way to print out progress messages and
-;;; such like. We clear the current error context so that we know that
-;;; it needs to be reprinted, and we also Force-Output so that the
-;;; message gets seen right away.
-(declaim (ftype (function (string &rest t) (values)) compiler-mumble))
-(defun compiler-mumble (format-string &rest format-args)
-  (note-message-repeats)
-  (setq *last-error-context* nil)
-  (apply #'format *error-output* format-string format-args)
-  (force-output *error-output*)
-  (values))
-
-;;; Return a string that somehow names the code in COMPONENT. We use
-;;; the source path for the bind node for an arbitrary entry point to
-;;; find the source context, then return that as a string.
-(declaim (ftype (function (component) simple-string) find-component-name))
-(defun find-component-name (component)
-  (let ((ep (first (block-succ (component-head component)))))
-    (aver ep) ; else no entry points??
-    (multiple-value-bind (form context)
-       (find-original-source
-        (node-source-path (continuation-next (block-start ep))))
-      (declare (ignore form))
-      (let ((*print-level* 2)
-           (*print-pretty* nil))
-       (format nil "~{~{~S~^ ~}~^ => ~}" context)))))
-\f
-;;;; condition system interface
-
-;;; Keep track of how many times each kind of condition happens.
-(defvar *compiler-error-count*)
-(defvar *compiler-warning-count*)
-(defvar *compiler-style-warning-count*)
-(defvar *compiler-note-count*)
-
-;;; Keep track of whether any surrounding COMPILE or COMPILE-FILE call
-;;; should return WARNINGS-P or FAILURE-P.
-(defvar *failure-p*)
-(defvar *warnings-p*)
-
-;;; condition handlers established by the compiler. We re-signal the
-;;; condition, then if it isn't handled, we increment our warning
-;;; counter and print the error message.
-(defun compiler-error-handler (condition)
-  (signal condition)
-  (incf *compiler-error-count*)
-  (setf *warnings-p* t
-       *failure-p* t)
-  (print-compiler-condition condition)
-  (continue condition))
-(defun compiler-warning-handler (condition)
-  (signal condition)
-  (incf *compiler-warning-count*)
-  (setf *warnings-p* t
-       *failure-p* t)
-  (print-compiler-condition condition)
-  (muffle-warning condition))
-(defun compiler-style-warning-handler (condition)
-  (signal condition)
-  (incf *compiler-style-warning-count*)
-  (setf *warnings-p* t)
-  (print-compiler-condition condition)
-  (muffle-warning condition))
-\f
-;;;; undefined warnings
-
-(defvar *undefined-warning-limit* 3
-  #!+sb-doc
-  "If non-null, then an upper limit on the number of unknown function or type
-  warnings that the compiler will print for any given name in a single
-  compilation. This prevents excessive amounts of output when the real
-  problem is a missing definition (as opposed to a typo in the use.)")
-
-;;; Make an entry in the *UNDEFINED-WARNINGS* describing a reference
-;;; to NAME of the specified KIND. If we have exceeded the warning
-;;; limit, then just increment the count, otherwise note the current
-;;; error context.
-;;;
-;;; Undefined types are noted by a condition handler in
-;;; WITH-COMPILATION-UNIT, which can potentially be invoked outside
-;;; the compiler, hence the BOUNDP check.
-(defun note-undefined-reference (name kind)
-  (unless (and
-          ;; Check for boundness so we don't blow up if we're called
-          ;; when IR1 conversion isn't going on.
-          (boundp '*lexenv*)
-          ;; FIXME: I'm pretty sure the INHIBIT-WARNINGS test below
-          ;; isn't a good idea; we should have INHIBIT-WARNINGS
-          ;; affect compiler notes, not STYLE-WARNINGs. And I'm not
-          ;; sure what the BOUNDP '*LEXENV* test above is for; it's
-          ;; likely a good idea, but it probably deserves an
-          ;; explanatory comment.
-          (policy *lexenv* (= inhibit-warnings 3)))
-    (let* ((found (dolist (warning *undefined-warnings* nil)
-                   (when (and (equal (undefined-warning-name warning) name)
-                              (eq (undefined-warning-kind warning) kind))
-                     (return warning))))
-          (res (or found
-                   (make-undefined-warning :name name :kind kind))))
-      (unless found (push res *undefined-warnings*))
-      (when (or (not *undefined-warning-limit*)
-               (< (undefined-warning-count res) *undefined-warning-limit*))
-       (push (find-error-context (list name))
-             (undefined-warning-warnings res)))
-      (incf (undefined-warning-count res))))
-  (values))
-\f
 ;;;; careful call
 
 ;;; Apply a function to some arguments, returning a list of the values
index a347996..410fdfd 100644 (file)
       (link-blocks call-block bind-block)
       next-block)))
 
-;;; Handle the environment semantics of LET conversion. We add the
-;;; lambda and its LETs to LETs for the CALL's home function. We merge
-;;; the calls for FUN with the calls for the home function, removing
-;;; FUN in the process. We also merge the ENTRIES.
-;;;
-;;; We also unlink the function head from the component head and set
-;;; COMPONENT-REANALYZE to true to indicate that the DFO should be
-;;; recomputed.
-(defun merge-lets (fun call)
-
-  (declare (type clambda fun) (type basic-combination call))
-
-  (let ((component (block-component (node-block call))))
-    (unlink-blocks (component-head component) (node-block (lambda-bind fun)))
-    (setf (component-lambdas component)
-         (delete fun (component-lambdas component)))
-    (setf (component-reanalyze component) t))
-  (setf (lambda-call-lexenv fun) (node-lexenv call))
-
+;;; Remove FUN from the tail set of anything it used to be in the
+;;; same set as; but leave FUN with a valid tail set value of
+;;; its own, for the benefit of code which might try to pull
+;;; something out of it (e.g. return type).
+(defun depart-from-tail-set (fun)
   ;; Until sbcl-0.pre7.37.flaky5.2, we did
   ;;   (LET ((TAILS (LAMBDA-TAIL-SET FUN)))
   ;;     (SETF (TAIL-SET-FUNCTIONS TAILS)
   ;; To deal with this problem, we no longer NIL out 
   ;; (LAMBDA-TAIL-SET FUN) here. Instead:
   ;;   * If we're the only function in TAIL-SET-FUNCTIONS, it should
-  ;;     be safe to leave ourself linked to it, and vice versa.
+  ;;     be safe to leave ourself linked to it, and it to you.
   ;;   * If there are other functions in TAIL-SET-FUNCTIONS, then we're
   ;;     afraid of future optimizations on those functions causing
   ;;     the TAIL-SET object no longer to be valid to describe our
   ;;     return value. Thus, we delete ourselves from that object;
-  ;;     but we save a copy of the object for ourselves, for the use of
-  ;;     later code (e.g. FINALIZE-XEP-DEFINITION) which might want to
+  ;;     but we save a newly-allocated tail-set, derived from the old
+  ;;     one, for ourselves, for the use of later code (e.g.
+  ;;     FINALIZE-XEP-DEFINITION) which might want to
   ;;     know about our return type.
   (let* ((old-tail-set (lambda-tail-set fun))
         (old-tail-set-functions (tail-set-functions old-tail-set)))
       (let ((new-tail-set (copy-tail-set old-tail-set)))
        (setf (lambda-tail-set fun) new-tail-set
              (tail-set-functions new-tail-set) (list fun)))))
-  ;; The documentation on TAIL-SET-INFO doesn't tell whether it
-  ;; remains valid in this case, so we nuke it on the theory that
-  ;; missing information is less dangerous than incorrect information.
-  (setf (tail-set-info (lambda-tail-set fun)) nil)
+  ;; The documentation on TAIL-SET-INFO doesn't tell whether it could
+  ;; remain valid in this case, so we nuke it on the theory that
+  ;; missing information tends to be less dangerous than incorrect
+  ;; information.
+  (setf (tail-set-info (lambda-tail-set fun)) nil))
+
+;;; Handle the environment semantics of LET conversion. We add the
+;;; lambda and its LETs to LETs for the CALL's home function. We merge
+;;; the calls for FUN with the calls for the home function, removing
+;;; FUN in the process. We also merge the ENTRIES.
+;;;
+;;; We also unlink the function head from the component head and set
+;;; COMPONENT-REANALYZE to true to indicate that the DFO should be
+;;; recomputed.
+(defun merge-lets (fun call)
+
+  (declare (type clambda fun) (type basic-combination call))
+
+  (let ((component (block-component (node-block call))))
+    (unlink-blocks (component-head component) (node-block (lambda-bind fun)))
+    (setf (component-lambdas component)
+         (delete fun (component-lambdas component)))
+    (setf (component-reanalyze component) t))
+  (setf (lambda-call-lexenv fun) (node-lexenv call))
+
+  (depart-from-tail-set fun)
 
   (let* ((home (node-home-lambda call))
         (home-env (lambda-environment home)))
index 5992a75..51dc76f 100644 (file)
 
  ("src/code/defbangstruct")
 
+ ("src/code/funutils" :not-host)
+
  ;; This needs DEF!STRUCT, and is itself needed early so that structure
  ;; accessors and inline functions defined here can be compiled inline
  ;; later. (Avoiding full calls not only increases efficiency, but also
 
  ("src/code/target-signal" :not-host) ; needs OS-CONTEXT-T from x86-vm
 
- ("src/code/symbol"         :not-host)
- ("src/code/bignum"         :not-host)
- ("src/code/target-numbers" :not-host)
- ("src/code/float-trap"     :not-host)
- ("src/code/float"          :not-host)
- ("src/code/irrat"          :not-host)
+ ("src/code/symbol"     :not-host)
+ ("src/code/bignum"     :not-host)
+ ("src/code/numbers"    :not-host)
+ ("src/code/float-trap" :not-host)
+ ("src/code/float"      :not-host)
+ ("src/code/irrat"      :not-host)
 
  ("src/code/char")
  ("src/code/target-char" :not-host)
  ("src/compiler/main") ; needs DEFSTRUCT FASL-OUTPUT from dump.lisp
  ("src/compiler/target-main" :not-host)
  ("src/compiler/ir1tran")
+ ("src/compiler/ir1-translators")
  ("src/compiler/ir1util")
+ ("src/compiler/ir1report")
  ("src/compiler/ir1opt")
 
  ;; Compiling this file requires the macros SB!ASSEM:EMIT-LABEL and
index d740002..06d6b3b 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".)
 
-"0.pre7.45"
+"0.pre7.46"