0.8.0.3:
[sbcl.git] / src / compiler / srctran.lisp
index 8631e17..c1a53a9 100644 (file)
@@ -1,6 +1,6 @@
 ;;;; This file contains macro-like source transformations which
 ;;;; convert uses of certain functions into the canonical form desired
-;;;; within the compiler. ### and other IR1 transforms and stuff.
+;;;; within the compiler. FIXME: and other IR1 transforms and stuff.
 
 ;;;; This software is part of the SBCL system. See the README file for
 ;;;; more information.
 
 ;;; Convert into an IF so that IF optimizations will eliminate redundant
 ;;; negations.
-(def-source-transform not (x) `(if ,x nil t))
-(def-source-transform null (x) `(if ,x nil t))
+(define-source-transform not (x) `(if ,x nil t))
+(define-source-transform null (x) `(if ,x nil t))
 
 ;;; ENDP is just NULL with a LIST assertion. The assertion will be
 ;;; optimized away when SAFETY optimization is low; hopefully that
 ;;; is consistent with ANSI's "should return an error".
-(def-source-transform endp (x) `(null (the list ,x)))
+(define-source-transform endp (x) `(null (the list ,x)))
 
 ;;; We turn IDENTITY into PROG1 so that it is obvious that it just
 ;;; returns the first value of its argument. Ditto for VALUES with one
 ;;; arg.
-(def-source-transform identity (x) `(prog1 ,x))
-(def-source-transform values (x) `(prog1 ,x))
+(define-source-transform identity (x) `(prog1 ,x))
+(define-source-transform values (x) `(prog1 ,x))
 
-;;; Bind the values and make a closure that returns them.
-(def-source-transform constantly (value)
-  (let ((rest (gensym "CONSTANTLY-REST-")))
-    `(lambda (&rest ,rest)
-       (declare (ignore ,rest))
-       ,value)))
+;;; Bind the value and make a closure that returns it.
+(define-source-transform constantly (value)
+  (with-unique-names (rest n-value)
+    `(let ((,n-value ,value))
+      (lambda (&rest ,rest)
+       (declare (ignore ,rest))
+       ,n-value))))
 
 ;;; If the function has a known number of arguments, then return a
 ;;; lambda with the appropriate fixed number of args. If the
 ;;; destination is a FUNCALL, then do the &REST APPLY thing, and let
 ;;; MV optimization figure things out.
-(deftransform complement ((fun) * * :node node :when :both)
+(deftransform complement ((fun) * * :node node)
   "open code"
   (multiple-value-bind (min max)
-      (function-type-nargs (continuation-type fun))
+      (fun-type-nargs (continuation-type fun))
     (cond
      ((and min (eql min max))
       (let ((dums (make-gensym-list min)))
@@ -62,7 +63,7 @@
 
 ;;; Translate CxR into CAR/CDR combos.
 (defun source-transform-cxr (form)
-  (if (or (byte-compiling) (/= (length form) 2))
+  (if (/= (length form) 2)
       (values nil t)
       (let ((name (symbol-name (car form))))
        (do ((i (- (length name) 2) (1- i))
 ;;; whatever is right for them is right for us. FIFTH..TENTH turn into
 ;;; Nth, which can be expanded into a CAR/CDR later on if policy
 ;;; favors it.
-(def-source-transform first (x) `(car ,x))
-(def-source-transform rest (x) `(cdr ,x))
-(def-source-transform second (x) `(cadr ,x))
-(def-source-transform third (x) `(caddr ,x))
-(def-source-transform fourth (x) `(cadddr ,x))
-(def-source-transform fifth (x) `(nth 4 ,x))
-(def-source-transform sixth (x) `(nth 5 ,x))
-(def-source-transform seventh (x) `(nth 6 ,x))
-(def-source-transform eighth (x) `(nth 7 ,x))
-(def-source-transform ninth (x) `(nth 8 ,x))
-(def-source-transform tenth (x) `(nth 9 ,x))
+(define-source-transform first (x) `(car ,x))
+(define-source-transform rest (x) `(cdr ,x))
+(define-source-transform second (x) `(cadr ,x))
+(define-source-transform third (x) `(caddr ,x))
+(define-source-transform fourth (x) `(cadddr ,x))
+(define-source-transform fifth (x) `(nth 4 ,x))
+(define-source-transform sixth (x) `(nth 5 ,x))
+(define-source-transform seventh (x) `(nth 6 ,x))
+(define-source-transform eighth (x) `(nth 7 ,x))
+(define-source-transform ninth (x) `(nth 8 ,x))
+(define-source-transform tenth (x) `(nth 9 ,x))
 
 ;;; Translate RPLACx to LET and SETF.
-(def-source-transform rplaca (x y)
+(define-source-transform rplaca (x y)
   (once-only ((n-x x))
     `(progn
        (setf (car ,n-x) ,y)
        ,n-x)))
-(def-source-transform rplacd (x y)
+(define-source-transform rplacd (x y)
   (once-only ((n-x x))
     `(progn
        (setf (cdr ,n-x) ,y)
        ,n-x)))
 
-(def-source-transform nth (n l) `(car (nthcdr ,n ,l)))
+(define-source-transform nth (n l) `(car (nthcdr ,n ,l)))
 
 (defvar *default-nthcdr-open-code-limit* 6)
 (defvar *extreme-nthcdr-open-code-limit* 20)
 \f
 ;;;; arithmetic and numerology
 
-(def-source-transform plusp (x) `(> ,x 0))
-(def-source-transform minusp (x) `(< ,x 0))
-(def-source-transform zerop (x) `(= ,x 0))
+(define-source-transform plusp (x) `(> ,x 0))
+(define-source-transform minusp (x) `(< ,x 0))
+(define-source-transform zerop (x) `(= ,x 0))
 
-(def-source-transform 1+ (x) `(+ ,x 1))
-(def-source-transform 1- (x) `(- ,x 1))
+(define-source-transform 1+ (x) `(+ ,x 1))
+(define-source-transform 1- (x) `(- ,x 1))
 
-(def-source-transform oddp (x) `(not (zerop (logand ,x 1))))
-(def-source-transform evenp (x) `(zerop (logand ,x 1)))
+(define-source-transform oddp (x) `(not (zerop (logand ,x 1))))
+(define-source-transform evenp (x) `(zerop (logand ,x 1)))
 
 ;;; Note that all the integer division functions are available for
 ;;; inline expansion.
 
 (macrolet ((deffrob (fun)
-            `(def-source-transform ,fun (x &optional (y nil y-p))
+            `(define-source-transform ,fun (x &optional (y nil y-p))
                (declare (ignore y))
                (if y-p
                    (values nil t)
   #-sb-xc-host ; (See CROSS-FLOAT-INFINITY-KLUDGE.)
   (deffrob ceiling))
 
-(def-source-transform lognand (x y) `(lognot (logand ,x ,y)))
-(def-source-transform lognor (x y) `(lognot (logior ,x ,y)))
-(def-source-transform logandc1 (x y) `(logand (lognot ,x) ,y))
-(def-source-transform logandc2 (x y) `(logand ,x (lognot ,y)))
-(def-source-transform logorc1 (x y) `(logior (lognot ,x) ,y))
-(def-source-transform logorc2 (x y) `(logior ,x (lognot ,y)))
-(def-source-transform logtest (x y) `(not (zerop (logand ,x ,y))))
-(def-source-transform logbitp (index integer)
+(define-source-transform lognand (x y) `(lognot (logand ,x ,y)))
+(define-source-transform lognor (x y) `(lognot (logior ,x ,y)))
+(define-source-transform logandc1 (x y) `(logand (lognot ,x) ,y))
+(define-source-transform logandc2 (x y) `(logand ,x (lognot ,y)))
+(define-source-transform logorc1 (x y) `(logior (lognot ,x) ,y))
+(define-source-transform logorc2 (x y) `(logior ,x (lognot ,y)))
+(define-source-transform logtest (x y) `(not (zerop (logand ,x ,y))))
+(define-source-transform logbitp (index integer)
   `(not (zerop (logand (ash 1 ,index) ,integer))))
-(def-source-transform byte (size position) `(cons ,size ,position))
-(def-source-transform byte-size (spec) `(car ,spec))
-(def-source-transform byte-position (spec) `(cdr ,spec))
-(def-source-transform ldb-test (bytespec integer)
+(define-source-transform byte (size position)
+  `(cons ,size ,position))
+(define-source-transform byte-size (spec) `(car ,spec))
+(define-source-transform byte-position (spec) `(cdr ,spec))
+(define-source-transform ldb-test (bytespec integer)
   `(not (zerop (mask-field ,bytespec ,integer))))
 
 ;;; With the ratio and complex accessors, we pick off the "identity"
 ;;; case, and use a primitive to handle the cell access case.
-(def-source-transform numerator (num)
+(define-source-transform numerator (num)
   (once-only ((n-num `(the rational ,num)))
     `(if (ratiop ,n-num)
         (%numerator ,n-num)
         ,n-num)))
-(def-source-transform denominator (num)
+(define-source-transform denominator (num)
   (once-only ((n-num `(the rational ,num)))
     `(if (ratiop ,n-num)
         (%denominator ,n-num)
                        ;; The bound exists, so keep it open still.
                        (list new-val))))
                   (t
-                   (error "Unknown bound type in make-interval!")))))
+                   (error "unknown bound type in MAKE-INTERVAL")))))
     (%make-interval :low (normalize-bound low)
                    :high (normalize-bound high))))
 
 ;;; Apply the function F to a bound X. If X is an open bound, then
 ;;; the result will be open. IF X is NIL, the result is NIL.
 (defun bound-func (f x)
+  (declare (type function f))
   (and x
        (with-float-traps-masked (:underflow :overflow :inexact :divide-by-zero)
         ;; With these traps masked, we might get things like infinity
 (defun interval-bounded-p (x how)
   (declare (type interval x))
   (ecase how
-    ('above
+    (above
      (interval-high x))
-    ('below
+    (below
      (interval-low x))
-    ('both
+    (both
      (and (interval-low x) (interval-high x)))))
 
 ;;; signed zero comparison functions. Use these functions if we need
              :low (bound-mul (interval-low x) (interval-low y))
              :high (bound-mul (interval-high x) (interval-high y))))
            (t
-            (error "This shouldn't happen!"))))))
+            (bug "excluded case in INTERVAL-MUL"))))))
 
 ;;; Divide two intervals.
 (defun interval-div (top bot)
              :low (bound-div (interval-low top) (interval-high bot) t)
              :high (bound-div (interval-high top) (interval-low bot) nil)))
            (t
-            (error "This shouldn't happen!"))))))
+            (bug "excluded case in INTERVAL-DIV"))))))
 
 ;;; Apply the function F to the interval X. If X = [a, b], then the
 ;;; result is [f(a), f(b)]. It is up to the user to make sure the
 ;;; result makes sense. It will if F is monotonic increasing (or
 ;;; non-decreasing).
 (defun interval-func (f x)
-  (declare (type interval x))
+  (declare (type function f)
+           (type interval x))
   (let ((lo (bound-func f (interval-low x)))
        (hi (bound-func f (interval-high x))))
     (make-interval :low lo :high hi)))
 (defun interval-abs (x)
   (declare (type interval x))
   (case (interval-range-info x)
-    ('+
+    (+
      (copy-interval x))
-    ('-
+    (-
      (interval-neg x))
     (t
      (destructuring-bind (x- x+) (interval-split 0 x t t)
 ;;; are equal to an intermediate convention for which they are
 ;;; considered different which is more natural for some of the
 ;;; optimisers.
-#!-negative-zero-is-not-zero
 (defun convert-numeric-type (type)
   (declare (type numeric-type type))
   ;;; Only convert real float interval delimiters types.
             :low (if lo-float-zero-p
                      (if (consp lo)
                          (list (float 0.0 lo-val))
-                         (float -0.0 lo-val))
+                         (float (load-time-value (make-unportable-float :single-float-negative-zero)) lo-val))
                      lo)
             :high (if hi-float-zero-p
                       (if (consp hi)
-                          (list (float -0.0 hi-val))
+                          (list (float (load-time-value (make-unportable-float :single-float-negative-zero)) hi-val))
                           (float 0.0 hi-val))
                       hi))
            type))
 ;;; Convert back from the intermediate convention for which -0.0 and
 ;;; 0.0 are considered different to the standard type convention for
 ;;; which and equal.
-#!-negative-zero-is-not-zero
 (defun convert-back-numeric-type (type)
   (declare (type numeric-type type))
   ;;; Only convert real float interval delimiters types.
       type))
 
 ;;; Convert back a possible list of numeric types.
-#!-negative-zero-is-not-zero
 (defun convert-back-numeric-type-list (type-list)
   (typecase type-list
     (list
 
 ;;; FIXME: MAKE-CANONICAL-UNION-TYPE and CONVERT-MEMBER-TYPE probably
 ;;; belong in the kernel's type logic, invoked always, instead of in
-;;; the compiler, invoked only during some type optimizations.
+;;; the compiler, invoked only during some type optimizations. (In
+;;; fact, as of 0.pre8.100 or so they probably are, under
+;;; MAKE-MEMBER-TYPE, so probably this code can be deleted)
 
 ;;; Take a list of types and return a canonical type specifier,
 ;;; combining any MEMBER types together. If both positive and negative
          (setf members (union members (member-type-members type)))
          (push type misc-types)))
     #!+long-float
-    (when (null (set-difference '(-0l0 0l0) members))
-      #!-negative-zero-is-not-zero
-      (push (specifier-type '(long-float 0l0 0l0)) misc-types)
-      #!+negative-zero-is-not-zero
-      (push (specifier-type '(long-float -0l0 0l0)) misc-types)
-      (setf members (set-difference members '(-0l0 0l0))))
-    (when (null (set-difference '(-0d0 0d0) members))
-      #!-negative-zero-is-not-zero
-      (push (specifier-type '(double-float 0d0 0d0)) misc-types)
-      #!+negative-zero-is-not-zero
-      (push (specifier-type '(double-float -0d0 0d0)) misc-types)
-      (setf members (set-difference members '(-0d0 0d0))))
-    (when (null (set-difference '(-0f0 0f0) members))
-      #!-negative-zero-is-not-zero
-      (push (specifier-type '(single-float 0f0 0f0)) misc-types)
-      #!+negative-zero-is-not-zero
-      (push (specifier-type '(single-float -0f0 0f0)) misc-types)
-      (setf members (set-difference members '(-0f0 0f0))))
+    (when (null (set-difference `(,(load-time-value (make-unportable-float :long-float-negative-zero)) 0.0l0) members))
+      (push (specifier-type '(long-float 0.0l0 0.0l0)) misc-types)
+      (setf members (set-difference members `(,(load-time-value (make-unportable-float :long-float-negative-zero)) 0.0l0))))
+    (when (null (set-difference `(,(load-time-value (make-unportable-float :double-float-negative-zero)) 0.0d0) members))
+      (push (specifier-type '(double-float 0.0d0 0.0d0)) misc-types)
+      (setf members (set-difference members `(,(load-time-value (make-unportable-float :double-float-negative-zero)) 0.0d0))))
+    (when (null (set-difference `(,(load-time-value (make-unportable-float :single-float-negative-zero)) 0.0f0) members))
+      (push (specifier-type '(single-float 0.0f0 0.0f0)) misc-types)
+      (setf members (set-difference members `(,(load-time-value (make-unportable-float :single-float-negative-zero)) 0.0f0))))
     (if members
        (apply #'type-union (make-member-type :members members) misc-types)
        (apply #'type-union misc-types))))
 (defun one-arg-derive-type (arg derive-fcn member-fcn
                                &optional (convert-type t))
   (declare (type function derive-fcn)
-          (type (or null function) member-fcn)
-          #!+negative-zero-is-not-zero (ignore convert-type))
+          (type (or null function) member-fcn))
   (let ((arg-list (prepare-arg-for-derive-type (continuation-type arg))))
     (when arg-list
       (flet ((deriver (x)
                      ;; Otherwise convert to a numeric type.
                      (let ((result-type-list
                             (funcall derive-fcn (convert-member-type x))))
-                       #!-negative-zero-is-not-zero
                        (if convert-type
                            (convert-back-numeric-type-list result-type-list)
-                           result-type-list)
-                       #!+negative-zero-is-not-zero
-                       result-type-list)))
+                           result-type-list))))
                 (numeric-type
-                 #!-negative-zero-is-not-zero
                  (if convert-type
                      (convert-back-numeric-type-list
                       (funcall derive-fcn (convert-numeric-type x)))
-                     (funcall derive-fcn x))
-                 #!+negative-zero-is-not-zero
-                 (funcall derive-fcn x))
+                     (funcall derive-fcn x)))
                 (t
                  *universal-type*))))
        ;; Run down the list of args and derive the type of each one,
 ;;; positive. If we didn't do this, we wouldn't be able to tell.
 (defun two-arg-derive-type (arg1 arg2 derive-fcn fcn
                                 &optional (convert-type t))
-  #!+negative-zero-is-not-zero
-  (declare (ignore convert-type))
-  (flet (#!-negative-zero-is-not-zero
-        (deriver (x y same-arg)
+  (declare (type function derive-fcn fcn))
+  (flet ((deriver (x y same-arg)
           (cond ((and (member-type-p x) (member-type-p y))
                  (let* ((x (first (member-type-members x)))
                         (y (first (member-type-members y)))
                        (convert-back-numeric-type-list result)
                        result)))
                 (t
-                 *universal-type*)))
-        #!+negative-zero-is-not-zero
-        (deriver (x y same-arg)
-          (cond ((and (member-type-p x) (member-type-p y))
-                 (let* ((x (first (member-type-members x)))
-                        (y (first (member-type-members y)))
-                        (result (with-float-traps-masked
-                                    (:underflow :overflow :divide-by-zero)
-                                  (funcall fcn x y))))
-                   (if result
-                       (make-member-type :members (list result)))))
-                ((and (member-type-p x) (numeric-type-p y))
-                 (let ((x (convert-member-type x)))
-                   (funcall derive-fcn x y same-arg)))
-                ((and (numeric-type-p x) (member-type-p y))
-                 (let ((y (convert-member-type y)))
-                   (funcall derive-fcn x y same-arg)))
-                ((and (numeric-type-p x) (numeric-type-p y))
-                 (funcall derive-fcn x y same-arg))
-                (t
                  *universal-type*))))
     (let ((same-arg (same-leaf-ref-p arg1 arg2))
          (a1 (prepare-arg-for-derive-type (continuation-type arg1)))
 
 ) ; PROGN
 
-
-;;; KLUDGE: All this ASH optimization is suppressed under CMU CL
-;;; because as of version 2.4.6 for Debian, CMU CL blows up on (ASH
-;;; 1000000000 -100000000000) (i.e. ASH of two bignums yielding zero)
-;;; and it's hard to avoid that calculation in here.
-#-(and cmu sb-xc-host)
-(progn
-
 (defun ash-derive-type-aux (n-type shift same-arg)
   (declare (ignore same-arg))
+  ;; KLUDGE: All this ASH optimization is suppressed under CMU CL for
+  ;; some bignum cases because as of version 2.4.6 for Debian and 18d,
+  ;; CMU CL blows up on (ASH 1000000000 -100000000000) (i.e. ASH of
+  ;; two bignums yielding zero) and it's hard to avoid that
+  ;; calculation in here.
+  #+(and cmu sb-xc-host)
+  (when (and (or (typep (numeric-type-low n-type) 'bignum)
+                (typep (numeric-type-high n-type) 'bignum))
+            (or (typep (numeric-type-low shift) 'bignum)
+                (typep (numeric-type-high shift) 'bignum)))
+    (return-from ash-derive-type-aux *universal-type*))
   (flet ((ash-outer (n s)
           (when (and (fixnump s)
                      (<= s 64)
-                     (> s sb!vm:*target-most-negative-fixnum*))
+                     (> s sb!xc:most-negative-fixnum))
             (ash n s)))
          ;; KLUDGE: The bare 64's here should be related to
          ;; symbolic machine word size values somehow.
 
         (ash-inner (n s)
           (if (and (fixnump s)
-                   (> s sb!vm:*target-most-negative-fixnum*))
+                   (> s sb!xc:most-negative-fixnum))
              (ash n (min s 64))
              (if (minusp n) -1 0))))
     (or (and (csubtypep n-type (specifier-type 'integer))
 
 (defoptimizer (ash derive-type) ((n shift))
   (two-arg-derive-type n shift #'ash-derive-type-aux #'ash))
-) ; PROGN
 
 #+sb-xc-host ; (See CROSS-FLOAT-INFINITY-KLUDGE.)
 (macrolet ((frob (fun)
 
 ;;; Define optimizers for FLOOR and CEILING.
 (macrolet
-    ((frob-opt (name q-name r-name)
+    ((def (name q-name r-name)
        (let ((q-aux (symbolicate q-name "-AUX"))
             (r-aux (symbolicate r-name "-AUX")))
         `(progn
                 (when (and quot rem)
                   (make-values-type :required (list quot rem))))))))))
 
-  ;; FIXME: DEF-FROB-OPT, not just FROB-OPT
-  (frob-opt floor floor-quotient-bound floor-rem-bound)
-  (frob-opt ceiling ceiling-quotient-bound ceiling-rem-bound))
+  (def floor floor-quotient-bound floor-rem-bound)
+  (def ceiling ceiling-quotient-bound ceiling-rem-bound))
 
 ;;; Define optimizers for FFLOOR and FCEILING
-(macrolet
-    ((frob-opt (name q-name r-name)
-       (let ((q-aux (symbolicate "F" q-name "-AUX"))
-            (r-aux (symbolicate r-name "-AUX")))
-        `(progn
-          ;; Compute type of quotient (first) result.
-          (defun ,q-aux (number-type divisor-type)
-            (let* ((number-interval
-                    (numeric-type->interval number-type))
-                   (divisor-interval
-                    (numeric-type->interval divisor-type))
-                   (quot (,q-name (interval-div number-interval
-                                                divisor-interval)))
-                   (res-type (numeric-contagion number-type divisor-type)))
-              (make-numeric-type
-               :class (numeric-type-class res-type)
-               :format (numeric-type-format res-type)
-               :low  (interval-low quot)
-               :high (interval-high quot))))
-
-          (defoptimizer (,name derive-type) ((number divisor))
-            (flet ((derive-q (n d same-arg)
-                     (declare (ignore same-arg))
-                     (if (and (numeric-type-real-p n)
-                              (numeric-type-real-p d))
-                         (,q-aux n d)
-                         *empty-type*))
-                   (derive-r (n d same-arg)
-                     (declare (ignore same-arg))
-                     (if (and (numeric-type-real-p n)
-                              (numeric-type-real-p d))
-                         (,r-aux n d)
-                         *empty-type*)))
-              (let ((quot (two-arg-derive-type
-                           number divisor #'derive-q #',name))
-                    (rem (two-arg-derive-type
-                          number divisor #'derive-r #'mod)))
-                (when (and quot rem)
-                  (make-values-type :required (list quot rem))))))))))
-
-  ;; FIXME: DEF-FROB-OPT, not just FROB-OPT
-  (frob-opt ffloor floor-quotient-bound floor-rem-bound)
-  (frob-opt fceiling ceiling-quotient-bound ceiling-rem-bound))
+(macrolet ((def (name q-name r-name)
+            (let ((q-aux (symbolicate "F" q-name "-AUX"))
+                  (r-aux (symbolicate r-name "-AUX")))
+              `(progn
+                 ;; Compute type of quotient (first) result.
+                 (defun ,q-aux (number-type divisor-type)
+                   (let* ((number-interval
+                           (numeric-type->interval number-type))
+                          (divisor-interval
+                           (numeric-type->interval divisor-type))
+                          (quot (,q-name (interval-div number-interval
+                                                       divisor-interval)))
+                          (res-type (numeric-contagion number-type
+                                                       divisor-type)))
+                     (make-numeric-type
+                      :class (numeric-type-class res-type)
+                      :format (numeric-type-format res-type)
+                      :low  (interval-low quot)
+                      :high (interval-high quot))))
+
+                 (defoptimizer (,name derive-type) ((number divisor))
+                   (flet ((derive-q (n d same-arg)
+                            (declare (ignore same-arg))
+                            (if (and (numeric-type-real-p n)
+                                     (numeric-type-real-p d))
+                                (,q-aux n d)
+                                *empty-type*))
+                          (derive-r (n d same-arg)
+                            (declare (ignore same-arg))
+                            (if (and (numeric-type-real-p n)
+                                     (numeric-type-real-p d))
+                                (,r-aux n d)
+                                *empty-type*)))
+                     (let ((quot (two-arg-derive-type
+                                  number divisor #'derive-q #',name))
+                           (rem (two-arg-derive-type
+                                 number divisor #'derive-r #'mod)))
+                       (when (and quot rem)
+                         (make-values-type :required (list quot rem))))))))))
+
+  (def ffloor floor-quotient-bound floor-rem-bound)
+  (def fceiling ceiling-quotient-bound ceiling-rem-bound))
 
 ;;; functions to compute the bounds on the quotient and remainder for
 ;;; the FLOOR function
 
 (defoptimizer (values derive-type) ((&rest values))
   (values-specifier-type
-   `(values ,@(mapcar #'(lambda (x)
-                         (type-specifier (continuation-type x)))
+   `(values ,@(mapcar (lambda (x)
+                       (type-specifier (continuation-type x)))
                      values))))
 \f
 ;;;; byte operations
                          `(let ((,,temp ,,spec))
                             ,,@body))))))
 
-  (def-source-transform ldb (spec int)
+  (define-source-transform ldb (spec int)
     (with-byte-specifier (size pos spec)
       `(%ldb ,size ,pos ,int)))
 
-  (def-source-transform dpb (newbyte spec int)
+  (define-source-transform dpb (newbyte spec int)
     (with-byte-specifier (size pos spec)
       `(%dpb ,newbyte ,size ,pos ,int)))
 
-  (def-source-transform mask-field (spec int)
+  (define-source-transform mask-field (spec int)
     (with-byte-specifier (size pos spec)
       `(%mask-field ,size ,pos ,int)))
 
-  (def-source-transform deposit-field (newbyte spec int)
+  (define-source-transform deposit-field (newbyte spec int)
     (with-byte-specifier (size pos spec)
       `(%deposit-field ,newbyte ,size ,pos ,int))))
 
     (if (and (numeric-type-p size)
             (csubtypep size (specifier-type 'integer)))
        (let ((size-high (numeric-type-high size)))
-         (if (and size-high (<= size-high sb!vm:word-bits))
+         (if (and size-high (<= size-high sb!vm:n-word-bits))
              (specifier-type `(unsigned-byte ,size-high))
              (specifier-type 'unsigned-byte)))
        *universal-type*)))
        (let ((size-high (numeric-type-high size))
              (posn-high (numeric-type-high posn)))
          (if (and size-high posn-high
-                  (<= (+ size-high posn-high) sb!vm:word-bits))
+                  (<= (+ size-high posn-high) sb!vm:n-word-bits))
              (specifier-type `(unsigned-byte ,(+ size-high posn-high)))
              (specifier-type 'unsigned-byte)))
        *universal-type*)))
              (high (numeric-type-high int))
              (low (numeric-type-low int)))
          (if (and size-high posn-high high low
-                  (<= (+ size-high posn-high) sb!vm:word-bits))
+                  (<= (+ size-high posn-high) sb!vm:n-word-bits))
              (specifier-type
               (list (if (minusp low) 'signed-byte 'unsigned-byte)
                     (max (integer-length high)
              (high (numeric-type-high int))
              (low (numeric-type-low int)))
          (if (and size-high posn-high high low
-                  (<= (+ size-high posn-high) sb!vm:word-bits))
+                  (<= (+ size-high posn-high) sb!vm:n-word-bits))
              (specifier-type
               (list (if (minusp low) 'signed-byte 'unsigned-byte)
                     (max (integer-length high)
 
 (deftransform %ldb ((size posn int)
                    (fixnum fixnum integer)
-                   (unsigned-byte #.sb!vm:word-bits))
+                   (unsigned-byte #.sb!vm:n-word-bits))
   "convert to inline logical operations"
   `(logand (ash int (- posn))
-          (ash ,(1- (ash 1 sb!vm:word-bits))
-               (- size ,sb!vm:word-bits))))
+          (ash ,(1- (ash 1 sb!vm:n-word-bits))
+               (- size ,sb!vm:n-word-bits))))
 
 (deftransform %mask-field ((size posn int)
                           (fixnum fixnum integer)
-                          (unsigned-byte #.sb!vm:word-bits))
+                          (unsigned-byte #.sb!vm:n-word-bits))
   "convert to inline logical operations"
   `(logand int
-          (ash (ash ,(1- (ash 1 sb!vm:word-bits))
-                    (- size ,sb!vm:word-bits))
+          (ash (ash ,(1- (ash 1 sb!vm:n-word-bits))
+                    (- size ,sb!vm:n-word-bits))
                posn)))
 
 ;;; Note: for %DPB and %DEPOSIT-FIELD, we can't use
 
 (deftransform %dpb ((new size posn int)
                    *
-                   (unsigned-byte #.sb!vm:word-bits))
+                   (unsigned-byte #.sb!vm:n-word-bits))
   "convert to inline logical operations"
   `(let ((mask (ldb (byte size 0) -1)))
      (logior (ash (logand new mask) posn)
 
 (deftransform %dpb ((new size posn int)
                    *
-                   (signed-byte #.sb!vm:word-bits))
+                   (signed-byte #.sb!vm:n-word-bits))
   "convert to inline logical operations"
   `(let ((mask (ldb (byte size 0) -1)))
      (logior (ash (logand new mask) posn)
 
 (deftransform %deposit-field ((new size posn int)
                              *
-                             (unsigned-byte #.sb!vm:word-bits))
+                             (unsigned-byte #.sb!vm:n-word-bits))
   "convert to inline logical operations"
   `(let ((mask (ash (ldb (byte size 0) -1) posn)))
      (logior (logand new mask)
 
 (deftransform %deposit-field ((new size posn int)
                              *
-                             (signed-byte #.sb!vm:word-bits))
+                             (signed-byte #.sb!vm:n-word-bits))
   "convert to inline logical operations"
   `(let ((mask (ash (ldb (byte size 0) -1) posn)))
      (logior (logand new mask)
 (deftransform commutative-arg-swap ((x y) * * :defun-only t :node node)
   (if (and (constant-continuation-p x)
           (not (constant-continuation-p y)))
-      `(,(continuation-function-name (basic-combination-fun node))
+      `(,(continuation-fun-name (basic-combination-fun node))
        y
        ,(continuation-value x))
       (give-up-ir1-transform)))
                 "place constant arg last"))
 
 ;;; Handle the case of a constant BOOLE-CODE.
-(deftransform boole ((op x y) * * :when :both)
+(deftransform boole ((op x y) * *)
   "convert to inline logical operations"
   (unless (constant-continuation-p op)
     (give-up-ir1-transform "BOOLE code is not a constant."))
 ;;;; converting special case multiply/divide to shifts
 
 ;;; If arg is a constant power of two, turn * into a shift.
-(deftransform * ((x y) (integer integer) * :when :both)
+(deftransform * ((x y) (integer integer) *)
   "convert x*2^k to shift"
   (unless (constant-continuation-p y)
     (give-up-ir1-transform))
     (or result 0)))
 
 ;;; If arg is a constant power of two, turn FLOOR into a shift and
-;;; mask. If CEILING, add in (1- (ABS Y)) and then do FLOOR.
+;;; mask. If CEILING, add in (1- (ABS Y)), do FLOOR and correct a
+;;; remainder.
 (flet ((frob (y ceil-p)
         (unless (constant-continuation-p y)
           (give-up-ir1-transform))
           (unless (= y-abs (ash 1 len))
             (give-up-ir1-transform))
           (let ((shift (- len))
-                (mask (1- y-abs)))
-            `(let ,(when ceil-p `((x (+ x ,(1- y-abs)))))
+                (mask (1- y-abs))
+                 (delta (if ceil-p (* (signum y) (1- y-abs)) 0)))
+            `(let ((x (+ x ,delta)))
                ,(if (minusp y)
                     `(values (ash (- x) ,shift)
-                             (- (logand (- x) ,mask)))
+                             (- (- (logand (- x) ,mask)) ,delta))
                     `(values (ash x ,shift)
-                             (logand x ,mask))))))))
+                             (- (logand x ,mask) ,delta))))))))
   (deftransform floor ((x y) (integer integer) *)
     "convert division by 2^k to shift"
     (frob y nil))
     (frob y t)))
 
 ;;; Do the same for MOD.
-(deftransform mod ((x y) (integer integer) * :when :both)
+(deftransform mod ((x y) (integer integer) *)
   "convert remainder mod 2^k to LOGAND"
   (unless (constant-continuation-p y)
     (give-up-ir1-transform))
                   (logand x ,mask))))))
 
 ;;; And the same for REM.
-(deftransform rem ((x y) (integer integer) * :when :both)
+(deftransform rem ((x y) (integer integer) *)
   "convert remainder mod 2^k to LOGAND"
   (unless (constant-continuation-p y)
     (give-up-ir1-transform))
           (logand x ,mask)))))
 \f
 ;;;; arithmetic and logical identity operation elimination
-;;;;
-;;;; Flush calls to various arith functions that convert to the
-;;;; identity function or a constant.
-
-(dolist (stuff '((ash 0 x)
-                (logand -1 x)
-                (logand 0 0)
-                (logior 0 x)
-                (logior -1 -1)
-                (logxor -1 (lognot x))
-                (logxor 0 x)))
-  (destructuring-bind (name identity result) stuff
-    (deftransform name ((x y) `(* (constant-argument (member ,identity))) '*
-                       :eval-name t :when :both)
-      "fold identity operations"
-      result)))
+
+;;; Flush calls to various arith functions that convert to the
+;;; identity function or a constant.
+(macrolet ((def (name identity result)
+             `(deftransform ,name ((x y) (* (constant-arg (member ,identity))) *)
+                "fold identity operations"
+                ',result)))
+  (def ash 0 x)
+  (def logand -1 x)
+  (def logand 0 0)
+  (def logior 0 x)
+  (def logior -1 -1)
+  (def logxor -1 (lognot x))
+  (def logxor 0 x))
 
 ;;; These are restricted to rationals, because (- 0 0.0) is 0.0, not -0.0, and
 ;;; (* 0 -4.0) is -0.0.
-(deftransform - ((x y) ((constant-argument (member 0)) rational) *
-                :when :both)
+(deftransform - ((x y) ((constant-arg (member 0)) rational) *)
   "convert (- 0 x) to negate"
   '(%negate y))
-(deftransform * ((x y) (rational (constant-argument (member 0))) *
-                :when :both)
-  "convert (* x 0) to 0."
+(deftransform * ((x y) (rational (constant-arg (member 0))) *)
+  "convert (* x 0) to 0"
   0)
 
 ;;; Return T if in an arithmetic op including continuations X and Y,
 ;;;
 ;;; If y is not constant, not zerop, or is contagious, or a positive
 ;;; float +0.0 then give up.
-(deftransform + ((x y) (t (constant-argument t)) * :when :both)
+(deftransform + ((x y) (t (constant-arg t)) *)
   "fold zero arg"
   (let ((val (continuation-value y)))
     (unless (and (zerop val)
 ;;;
 ;;; If y is not constant, not zerop, or is contagious, or a negative
 ;;; float -0.0 then give up.
-(deftransform - ((x y) (t (constant-argument t)) * :when :both)
+(deftransform - ((x y) (t (constant-arg t)) *)
   "fold zero arg"
   (let ((val (continuation-value y)))
     (unless (and (zerop val)
   'x)
 
 ;;; Fold (OP x +/-1)
-(dolist (stuff '((* x (%negate x))
-                (/ x (%negate x))
-                (expt x (/ 1 x))))
-  (destructuring-bind (name result minus-result) stuff
-    (deftransform name ((x y) '(t (constant-argument real)) '* :eval-name t
-                       :when :both)
-      "fold identity operations"
-      (let ((val (continuation-value y)))
-       (unless (and (= (abs val) 1)
-                    (not-more-contagious y x))
-         (give-up-ir1-transform))
-       (if (minusp val) minus-result result)))))
+(macrolet ((def (name result minus-result)
+             `(deftransform ,name ((x y) (t (constant-arg real)) *)
+                "fold identity operations"
+                (let ((val (continuation-value y)))
+                  (unless (and (= (abs val) 1)
+                               (not-more-contagious y x))
+                    (give-up-ir1-transform))
+                  (if (minusp val) ',minus-result ',result)))))
+  (def * x (%negate x))
+  (def / x (%negate x))
+  (def expt x (/ 1 x)))
 
 ;;; Fold (expt x n) into multiplications for small integral values of
 ;;; N; convert (expt x 1/2) to sqrt.
-(deftransform expt ((x y) (t (constant-argument real)) *)
+(deftransform expt ((x y) (t (constant-arg real)) *)
   "recode as multiplication or sqrt"
   (let ((val (continuation-value y)))
     ;; If Y would cause the result to be promoted to the same type as
 ;;; KLUDGE: Shouldn't (/ 0.0 0.0), etc. cause exceptions in these
 ;;; transformations?
 ;;; Perhaps we should have to prove that the denominator is nonzero before
-;;; doing them? (Also the DOLIST over macro calls is weird. Perhaps
-;;; just FROB?) -- WHN 19990917
-;;;
-;;; FIXME: What gives with the single quotes in the argument lists
-;;; for DEFTRANSFORMs here? Does that work? Is it needed? Why?
-(dolist (name '(ash /))
-  (deftransform name ((x y) '((constant-argument (integer 0 0)) integer) '*
-                     :eval-name t :when :both)
-    "fold zero arg"
-    0))
-(dolist (name '(truncate round floor ceiling))
-  (deftransform name ((x y) '((constant-argument (integer 0 0)) integer) '*
-                     :eval-name t :when :both)
-    "fold zero arg"
-    '(values 0 0)))
+;;; doing them?  -- WHN 19990917
+(macrolet ((def (name)
+             `(deftransform ,name ((x y) ((constant-arg (integer 0 0)) integer)
+                                   *)
+                "fold zero arg"
+                0)))
+  (def ash)
+  (def /))
+
+(macrolet ((def (name)
+             `(deftransform ,name ((x y) ((constant-arg (integer 0 0)) integer)
+                                   *)
+                "fold zero arg"
+                '(values 0 0))))
+  (def truncate)
+  (def round)
+  (def floor)
+  (def ceiling))
 \f
 ;;;; character operations
 
 ;;; if there is no intersection between the types of the arguments,
 ;;; then the result is definitely false.
 (deftransform simple-equality-transform ((x y) * *
-                                        :defun-only t
-                                        :when :both)
+                                        :defun-only t)
   (cond ((same-leaf-ref-p x y)
         t)
        ((not (types-equal-or-intersect (continuation-type x)
        (t
         (give-up-ir1-transform))))
 
-(dolist (x '(eq char= equal))
-  (%deftransform x '(function * *) #'simple-equality-transform))
+(macrolet ((def (x)
+             `(%deftransform ',x '(function * *) #'simple-equality-transform)))
+  (def eq)
+  (def char=)
+  (def equal))
 
-;;; Similar to SIMPLE-EQUALITY-PREDICATE, except that we also try to
-;;; convert to a type-specific predicate or EQ:
+;;; This is similar to SIMPLE-EQUALITY-PREDICATE, except that we also
+;;; try to convert to a type-specific predicate or EQ:
 ;;; -- If both args are characters, convert to CHAR=. This is better than
 ;;;    just converting to EQ, since CHAR= may have special compilation
 ;;;    strategies for non-standard representations, etc.
 ;;;    it second. These rules make it easier for the back end to match
 ;;;    these interesting cases.
 ;;; -- If Y is a fixnum, then we quietly pass because the back end can
-;;;    handle that case, otherwise give an efficency note.
-(deftransform eql ((x y) * * :when :both)
+;;;    handle that case, otherwise give an efficiency note.
+(deftransform eql ((x y) * *)
   "convert to simpler equality predicate"
   (let ((x-type (continuation-type x))
        (y-type (continuation-type y))
 
 ;;; Convert to EQL if both args are rational and complexp is specified
 ;;; and the same for both.
-(deftransform = ((x y) * * :when :both)
+(deftransform = ((x y) * *)
   "open code"
   (let ((x-type (continuation-type x))
        (y-type (continuation-type y)))
              (t
               (give-up-ir1-transform))))))
 
-(deftransform < ((x y) (integer integer) * :when :both)
+(deftransform < ((x y) (integer integer) *)
   (ir1-transform-< x y x y '>))
 
-(deftransform > ((x y) (integer integer) * :when :both)
+(deftransform > ((x y) (integer integer) *)
   (ir1-transform-< y x x y '<))
 
 #-sb-xc-host ; (See CROSS-FLOAT-INFINITY-KLUDGE.)
-(deftransform < ((x y) (float float) * :when :both)
+(deftransform < ((x y) (float float) *)
   (ir1-transform-< x y x y '>))
 
 #-sb-xc-host ; (See CROSS-FLOAT-INFINITY-KLUDGE.)
-(deftransform > ((x y) (float float) * :when :both)
+(deftransform > ((x y) (float float) *)
   (ir1-transform-< y x x y '<))
 \f
 ;;;; converting N-arg comparisons
               ((zerop i)
                `((lambda ,vars ,result) . ,args)))))))
 
-(def-source-transform = (&rest args) (multi-compare '= args nil))
-(def-source-transform < (&rest args) (multi-compare '< args nil))
-(def-source-transform > (&rest args) (multi-compare '> args nil))
-(def-source-transform <= (&rest args) (multi-compare '> args t))
-(def-source-transform >= (&rest args) (multi-compare '< args t))
+(define-source-transform = (&rest args) (multi-compare '= args nil))
+(define-source-transform < (&rest args) (multi-compare '< args nil))
+(define-source-transform > (&rest args) (multi-compare '> args nil))
+(define-source-transform <= (&rest args) (multi-compare '> args t))
+(define-source-transform >= (&rest args) (multi-compare '< args t))
 
-(def-source-transform char= (&rest args) (multi-compare 'char= args nil))
-(def-source-transform char< (&rest args) (multi-compare 'char< args nil))
-(def-source-transform char> (&rest args) (multi-compare 'char> args nil))
-(def-source-transform char<= (&rest args) (multi-compare 'char> args t))
-(def-source-transform char>= (&rest args) (multi-compare 'char< args t))
+(define-source-transform char= (&rest args) (multi-compare 'char= args nil))
+(define-source-transform char< (&rest args) (multi-compare 'char< args nil))
+(define-source-transform char> (&rest args) (multi-compare 'char> args nil))
+(define-source-transform char<= (&rest args) (multi-compare 'char> args t))
+(define-source-transform char>= (&rest args) (multi-compare 'char< args t))
 
-(def-source-transform char-equal (&rest args)
+(define-source-transform char-equal (&rest args)
   (multi-compare 'char-equal args nil))
-(def-source-transform char-lessp (&rest args)
+(define-source-transform char-lessp (&rest args)
   (multi-compare 'char-lessp args nil))
-(def-source-transform char-greaterp (&rest args)
+(define-source-transform char-greaterp (&rest args)
   (multi-compare 'char-greaterp args nil))
-(def-source-transform char-not-greaterp (&rest args)
+(define-source-transform char-not-greaterp (&rest args)
   (multi-compare 'char-greaterp args t))
-(def-source-transform char-not-lessp (&rest args)
+(define-source-transform char-not-lessp (&rest args)
   (multi-compare 'char-lessp args t))
 
 ;;; This function does source transformation of N-arg inequality
-;;; functions such as /=. This is similar to Multi-Compare in the <3
+;;; functions such as /=. This is similar to MULTI-COMPARE in the <3
 ;;; arg cases. If there are more than two args, then we expand into
 ;;; the appropriate n^2 comparisons only when speed is important.
 (declaim (ftype (function (symbol list) *) multi-not-equal))
                 (dolist (v2 next)
                   (setq result `(if (,predicate ,v1 ,v2) nil ,result))))))))))
 
-(def-source-transform /= (&rest args) (multi-not-equal '= args))
-(def-source-transform char/= (&rest args) (multi-not-equal 'char= args))
-(def-source-transform char-not-equal (&rest args)
+(define-source-transform /= (&rest args) (multi-not-equal '= args))
+(define-source-transform char/= (&rest args) (multi-not-equal 'char= args))
+(define-source-transform char-not-equal (&rest args)
   (multi-not-equal 'char-equal args))
 
+;;; FIXME: can go away once bug 194 is fixed and we can use (THE REAL X)
+;;; as God intended
+(defun error-not-a-real (x)
+  (error 'simple-type-error
+        :datum x
+        :expected-type 'real
+        :format-control "not a REAL: ~S"
+        :format-arguments (list x)))
+
 ;;; Expand MAX and MIN into the obvious comparisons.
-(def-source-transform max (arg &rest more-args)
-  (if (null more-args)
-      `(values ,arg)
-      (once-only ((arg1 arg)
-                 (arg2 `(max ,@more-args)))
-       `(if (> ,arg1 ,arg2)
-            ,arg1 ,arg2))))
-(def-source-transform min (arg &rest more-args)
-  (if (null more-args)
-      `(values ,arg)
-      (once-only ((arg1 arg)
-                 (arg2 `(min ,@more-args)))
-       `(if (< ,arg1 ,arg2)
-            ,arg1 ,arg2))))
+(define-source-transform max (arg0 &rest rest)
+  (once-only ((arg0 arg0))
+    (if (null rest)
+       `(values (the real ,arg0))
+       `(let ((maxrest (max ,@rest)))
+         (if (> ,arg0 maxrest) ,arg0 maxrest)))))
+(define-source-transform min (arg0 &rest rest)
+  (once-only ((arg0 arg0))
+    (if (null rest)
+       `(values (the real ,arg0))
+       `(let ((minrest (min ,@rest)))
+         (if (< ,arg0 minrest) ,arg0 minrest)))))
 \f
 ;;;; converting N-arg arithmetic functions
 ;;;;
 ;;;; versions, and degenerate cases are flushed.
 
 ;;; Left-associate FIRST-ARG and MORE-ARGS using FUNCTION.
-(declaim (ftype (function (symbol t list) list) associate-arguments))
-(defun associate-arguments (function first-arg more-args)
+(declaim (ftype (function (symbol t list) list) associate-args))
+(defun associate-args (function first-arg more-args)
   (let ((next (rest more-args))
        (arg (first more-args)))
     (if (null next)
        `(,function ,first-arg ,arg)
-       (associate-arguments function `(,function ,first-arg ,arg) next))))
+       (associate-args function `(,function ,first-arg ,arg) next))))
 
 ;;; Do source transformations for transitive functions such as +.
 ;;; One-arg cases are replaced with the arg and zero arg cases with
-;;; the identity. If LEAF-FUN is true, then replace two-arg calls with
-;;; a call to that function.
-(defun source-transform-transitive (fun args identity &optional leaf-fun)
+;;; the identity.  ONE-ARG-RESULT-TYPE is, if non-NIL, the type to
+;;; ensure (with THE) that the argument in one-argument calls is.
+(defun source-transform-transitive (fun args identity
+                                   &optional one-arg-result-type)
   (declare (symbol fun leaf-fun) (list args))
   (case (length args)
     (0 identity)
-    (1 `(values ,(first args)))
-    (2 (if leaf-fun
-          `(,leaf-fun ,(first args) ,(second args))
-          (values nil t)))
+    (1 (if one-arg-result-type
+          `(values (the ,one-arg-result-type ,(first args)))
+          `(values ,(first args))))
+    (2 (values nil t))
     (t
-     (associate-arguments fun (first args) (rest args)))))
-
-(def-source-transform + (&rest args) (source-transform-transitive '+ args 0))
-(def-source-transform * (&rest args) (source-transform-transitive '* args 1))
-(def-source-transform logior (&rest args)
-  (source-transform-transitive 'logior args 0))
-(def-source-transform logxor (&rest args)
-  (source-transform-transitive 'logxor args 0))
-(def-source-transform logand (&rest args)
-  (source-transform-transitive 'logand args -1))
-
-(def-source-transform logeqv (&rest args)
+     (associate-args fun (first args) (rest args)))))
+
+(define-source-transform + (&rest args)
+  (source-transform-transitive '+ args 0 'number))
+(define-source-transform * (&rest args)
+  (source-transform-transitive '* args 1 'number))
+(define-source-transform logior (&rest args)
+  (source-transform-transitive 'logior args 0 'integer))
+(define-source-transform logxor (&rest args)
+  (source-transform-transitive 'logxor args 0 'integer))
+(define-source-transform logand (&rest args)
+  (source-transform-transitive 'logand args -1 'integer))
+
+(define-source-transform logeqv (&rest args)
   (if (evenp (length args))
       `(lognot (logxor ,@args))
       `(logxor ,@args)))
 ;;; because when they are given one argument, they return its absolute
 ;;; value.
 
-(def-source-transform gcd (&rest args)
+(define-source-transform gcd (&rest args)
   (case (length args)
     (0 0)
     (1 `(abs (the integer ,(first args))))
     (2 (values nil t))
-    (t (associate-arguments 'gcd (first args) (rest args)))))
+    (t (associate-args 'gcd (first args) (rest args)))))
 
-(def-source-transform lcm (&rest args)
+(define-source-transform lcm (&rest args)
   (case (length args)
     (0 1)
     (1 `(abs (the integer ,(first args))))
     (2 (values nil t))
-    (t (associate-arguments 'lcm (first args) (rest args)))))
+    (t (associate-args 'lcm (first args) (rest args)))))
 
 ;;; Do source transformations for intransitive n-arg functions such as
 ;;; /. With one arg, we form the inverse. With two args we pass.
 ;;; Otherwise we associate into two-arg calls.
-(declaim (ftype (function (symbol list t) list) source-transform-intransitive))
+(declaim (ftype (function (symbol list t)
+                          (values list &optional (member nil t)))
+                source-transform-intransitive))
 (defun source-transform-intransitive (function args inverse)
   (case (length args)
     ((0 2) (values nil t))
     (1 `(,@inverse ,(first args)))
-    (t (associate-arguments function (first args) (rest args)))))
+    (t (associate-args function (first args) (rest args)))))
 
-(def-source-transform - (&rest args)
+(define-source-transform - (&rest args)
   (source-transform-intransitive '- args '(%negate)))
-(def-source-transform / (&rest args)
+(define-source-transform / (&rest args)
   (source-transform-intransitive '/ args '(/ 1)))
 \f
 ;;;; transforming APPLY
 ;;; We convert APPLY into MULTIPLE-VALUE-CALL so that the compiler
 ;;; only needs to understand one kind of variable-argument call. It is
 ;;; more efficient to convert APPLY to MV-CALL than MV-CALL to APPLY.
-(def-source-transform apply (fun arg &rest more-args)
+(define-source-transform apply (fun arg &rest more-args)
   (let ((args (cons arg more-args)))
     `(multiple-value-call ,fun
-       ,@(mapcar #'(lambda (x)
-                    `(values ,x))
+       ,@(mapcar (lambda (x)
+                  `(values ,x))
                 (butlast args))
        (values-list ,(car (last args))))))
 \f
        nil)))
 
 (defoptimizer (coerce derive-type) ((value type))
-  (let ((value-type (continuation-type value))
-        (type-type (continuation-type type)))
-    (labels
-        ((good-cons-type-p (cons-type)
-           ;; Make sure the cons-type we're looking at is something
-           ;; we're prepared to handle which is basically something
-           ;; that array-element-type can return.
-           (or (and (member-type-p cons-type)
-                    (null (rest (member-type-members cons-type)))
-                    (null (first (member-type-members cons-type))))
-               (let ((car-type (cons-type-car-type cons-type)))
-                 (and (member-type-p car-type)
-                      (null (rest (member-type-members car-type)))
-                      (or (symbolp (first (member-type-members car-type)))
-                          (numberp (first (member-type-members car-type)))
-                          (and (listp (first (member-type-members car-type)))
-                               (numberp (first (first (member-type-members
-                                                       car-type))))))
-                      (good-cons-type-p (cons-type-cdr-type cons-type))))))
-         (unconsify-type (good-cons-type)
-           ;; Convert the "printed" respresentation of a cons
-           ;; specifier into a type specifier.  That is, the specifier
-           ;; (cons (eql signed-byte) (cons (eql 16) null)) is
-           ;; converted to (signed-byte 16).
-           (cond ((or (null good-cons-type)
-                      (eq good-cons-type 'null))
-                   nil)
-                 ((and (eq (first good-cons-type) 'cons)
-                       (eq (first (second good-cons-type)) 'member))
-                   `(,(second (second good-cons-type))
-                     ,@(unconsify-type (caddr good-cons-type))))))
-         (coerceable-p (c-type)
-           ;; Can the value be coerced to the given type?  Coerce is
-           ;; complicated, so we don't handle every possible case
-           ;; here---just the most common and easiest cases:
-           ;;
-           ;; o Any real can be coerced to a float type.
-           ;; o Any number can be coerced to a complex single/double-float.
-           ;; o An integer can be coerced to an integer.
-           (let ((coerced-type c-type))
-             (or (and (subtypep coerced-type 'float)
-                      (csubtypep value-type (specifier-type 'real)))
-                 (and (subtypep coerced-type
-                                '(or (complex single-float)
-                                  (complex double-float)))
-                      (csubtypep value-type (specifier-type 'number)))
-                 (and (subtypep coerced-type 'integer)
-                      (csubtypep value-type (specifier-type 'integer))))))
-         (process-types (type)
-           ;; FIXME
-           ;; This needs some work because we should be able to derive
-           ;; the resulting type better than just the type arg of
-           ;; coerce.  That is, if x is (integer 10 20), the (coerce x
-           ;; 'double-float) should say (double-float 10d0 20d0)
-           ;; instead of just double-float.
-           (cond ((member-type-p type)
-                   (let ((members (member-type-members type)))
-                     (if (every #'coerceable-p members)
-                       (specifier-type `(or ,@members))
-                       *universal-type*)))
-                 ((and (cons-type-p type)
-                       (good-cons-type-p type))
-                   (let ((c-type (unconsify-type (type-specifier type))))
-                     (if (coerceable-p c-type)
-                       (specifier-type c-type)
-                       *universal-type*)))
-                 (t
-                   *universal-type*))))
-      (cond ((union-type-p type-type)
-              (apply #'type-union (mapcar #'process-types
-                                          (union-type-types type-type))))
-            ((or (member-type-p type-type)
-                 (cons-type-p type-type))
-              (process-types type-type))
-            (t
-              *universal-type*)))))
+  (cond
+    ((constant-continuation-p type)
+     ;; This branch is essentially (RESULT-TYPE-SPECIFIER-NTH-ARG 2),
+     ;; but dealing with the niggle that complex canonicalization gets
+     ;; in the way: (COERCE 1 'COMPLEX) returns 1, which is not of
+     ;; type COMPLEX.
+     (let* ((specifier (continuation-value type))
+           (result-typeoid (careful-specifier-type specifier)))
+       (cond
+        ((null result-typeoid) nil)
+        ((csubtypep result-typeoid (specifier-type 'number))
+         ;; the difficult case: we have to cope with ANSI 12.1.5.3
+         ;; Rule of Canonical Representation for Complex Rationals,
+         ;; which is a truly nasty delivery to field.
+         (cond
+           ((csubtypep result-typeoid (specifier-type 'real))
+            ;; cleverness required here: it would be nice to deduce
+            ;; that something of type (INTEGER 2 3) coerced to type
+            ;; DOUBLE-FLOAT should return (DOUBLE-FLOAT 2.0d0 3.0d0).
+            ;; FLOAT gets its own clause because it's implemented as
+            ;; a UNION-TYPE, so we don't catch it in the NUMERIC-TYPE
+            ;; logic below.
+            result-typeoid)
+           ((and (numeric-type-p result-typeoid)
+                 (eq (numeric-type-complexp result-typeoid) :real))
+            ;; FIXME: is this clause (a) necessary or (b) useful?
+            result-typeoid)
+           ((or (csubtypep result-typeoid
+                           (specifier-type '(complex single-float)))
+                (csubtypep result-typeoid
+                           (specifier-type '(complex double-float)))
+                #!+long-float
+                (csubtypep result-typeoid
+                           (specifier-type '(complex long-float))))
+            ;; float complex types are never canonicalized.
+            result-typeoid)
+           (t
+            ;; if it's not a REAL, or a COMPLEX FLOAToid, it's
+            ;; probably just a COMPLEX or equivalent.  So, in that
+            ;; case, we will return a complex or an object of the
+            ;; provided type if it's rational:
+            (type-union result-typeoid
+                        (type-intersection (continuation-type value)
+                                           (specifier-type 'rational))))))
+        (t result-typeoid))))
+    (t
+     ;; OK, the result-type argument isn't constant.  However, there
+     ;; are common uses where we can still do better than just
+     ;; *UNIVERSAL-TYPE*: e.g. (COERCE X (ARRAY-ELEMENT-TYPE Y)),
+     ;; where Y is of a known type.  See messages on cmucl-imp
+     ;; 2001-02-14 and sbcl-devel 2002-12-12.  We only worry here
+     ;; about types that can be returned by (ARRAY-ELEMENT-TYPE Y), on
+     ;; the basis that it's unlikely that other uses are both
+     ;; time-critical and get to this branch of the COND (non-constant
+     ;; second argument to COERCE).  -- CSR, 2002-12-16
+     (let ((value-type (continuation-type value))
+          (type-type (continuation-type type)))
+       (labels
+          ((good-cons-type-p (cons-type)
+             ;; Make sure the cons-type we're looking at is something
+             ;; we're prepared to handle which is basically something
+             ;; that array-element-type can return.
+             (or (and (member-type-p cons-type)
+                      (null (rest (member-type-members cons-type)))
+                      (null (first (member-type-members cons-type))))
+                 (let ((car-type (cons-type-car-type cons-type)))
+                   (and (member-type-p car-type)
+                        (null (rest (member-type-members car-type)))
+                        (or (symbolp (first (member-type-members car-type)))
+                            (numberp (first (member-type-members car-type)))
+                            (and (listp (first (member-type-members
+                                                car-type)))
+                                 (numberp (first (first (member-type-members
+                                                         car-type))))))
+                        (good-cons-type-p (cons-type-cdr-type cons-type))))))
+           (unconsify-type (good-cons-type)
+             ;; Convert the "printed" respresentation of a cons
+             ;; specifier into a type specifier.  That is, the
+             ;; specifier (CONS (EQL SIGNED-BYTE) (CONS (EQL 16)
+             ;; NULL)) is converted to (SIGNED-BYTE 16).
+             (cond ((or (null good-cons-type)
+                        (eq good-cons-type 'null))
+                    nil)
+                   ((and (eq (first good-cons-type) 'cons)
+                         (eq (first (second good-cons-type)) 'member))
+                    `(,(second (second good-cons-type))
+                      ,@(unconsify-type (caddr good-cons-type))))))
+           (coerceable-p (c-type)
+             ;; Can the value be coerced to the given type?  Coerce is
+             ;; complicated, so we don't handle every possible case
+             ;; here---just the most common and easiest cases:
+             ;;
+             ;; * Any REAL can be coerced to a FLOAT type.
+             ;; * Any NUMBER can be coerced to a (COMPLEX
+             ;;   SINGLE/DOUBLE-FLOAT).
+             ;;
+             ;; FIXME I: we should also be able to deal with characters
+             ;; here.
+             ;;
+             ;; FIXME II: I'm not sure that anything is necessary
+             ;; here, at least while COMPLEX is not a specialized
+             ;; array element type in the system.  Reasoning: if
+             ;; something cannot be coerced to the requested type, an
+             ;; error will be raised (and so any downstream compiled
+             ;; code on the assumption of the returned type is
+             ;; unreachable).  If something can, then it will be of
+             ;; the requested type, because (by assumption) COMPLEX
+             ;; (and other difficult types like (COMPLEX INTEGER)
+             ;; aren't specialized types.
+             (let ((coerced-type c-type))
+               (or (and (subtypep coerced-type 'float)
+                        (csubtypep value-type (specifier-type 'real)))
+                   (and (subtypep coerced-type
+                                  '(or (complex single-float)
+                                       (complex double-float)))
+                        (csubtypep value-type (specifier-type 'number))))))
+           (process-types (type)
+             ;; FIXME: This needs some work because we should be able
+             ;; to derive the resulting type better than just the
+             ;; type arg of coerce.  That is, if X is (INTEGER 10
+             ;; 20), then (COERCE X 'DOUBLE-FLOAT) should say
+             ;; (DOUBLE-FLOAT 10d0 20d0) instead of just
+             ;; double-float.
+             (cond ((member-type-p type)
+                    (let ((members (member-type-members type)))
+                      (if (every #'coerceable-p members)
+                          (specifier-type `(or ,@members))
+                          *universal-type*)))
+                   ((and (cons-type-p type)
+                         (good-cons-type-p type))
+                    (let ((c-type (unconsify-type (type-specifier type))))
+                      (if (coerceable-p c-type)
+                          (specifier-type c-type)
+                          *universal-type*)))
+                   (t
+                    *universal-type*))))
+        (cond ((union-type-p type-type)
+               (apply #'type-union (mapcar #'process-types
+                                           (union-type-types type-type))))
+              ((or (member-type-p type-type)
+                   (cons-type-p type-type))
+               (process-types type-type))
+              (t
+               *universal-type*)))))))
+
+(defoptimizer (compile derive-type) ((nameoid function))
+  (when (csubtypep (continuation-type nameoid)
+                  (specifier-type 'null))
+    (values-specifier-type '(values function boolean boolean))))
 
+;;; FIXME: Maybe also STREAM-ELEMENT-TYPE should be given some loving
+;;; treatment along these lines? (See discussion in COERCE DERIVE-TYPE
+;;; optimizer, above).
 (defoptimizer (array-element-type derive-type) ((array))
-  (let* ((array-type (continuation-type array)))
-    #!+sb-show
-    (format t "~& defoptimizer array-elt-derive-type - array-element-type ~~
-~A~%" array-type)
+  (let ((array-type (continuation-type array)))
     (labels ((consify (list)
               (if (endp list)
                   '(eql nil)
                   `(cons (eql ,(car list)) ,(consify (rest list)))))
             (get-element-type (a)
-              (let ((element-type (type-specifier
-                                   (array-type-specialized-element-type a))))
-                (cond ((symbolp element-type)
+              (let ((element-type
+                    (type-specifier (array-type-specialized-element-type a))))
+                (cond ((eq element-type '*)
+                       (specifier-type 'type-specifier))
+                     ((symbolp element-type)
                        (make-member-type :members (list element-type)))
                       ((consp element-type)
                        (specifier-type (consify element-type)))
                       (t
-                       (error "Can't grok type ~A~%" element-type))))))
+                       (error "can't understand type ~S~%" element-type))))))
       (cond ((array-type-p array-type)
-            (get-element-type array-type))
-           ((union-type-p array-type)             
+            (get-element-type array-type))
+           ((union-type-p array-type)
              (apply #'type-union
                     (mapcar #'get-element-type (union-type-types array-type))))
-           (t
-            *universal-type*)))))
+           (t
+            *universal-type*)))))
+
+(define-source-transform sb!impl::sort-vector (vector start end predicate key)
+  `(macrolet ((%index (x) `(truly-the index ,x))
+             (%parent (i) `(ash ,i -1))
+             (%left (i) `(%index (ash ,i 1)))
+             (%right (i) `(%index (1+ (ash ,i 1))))
+             (%heapify (i)
+              `(do* ((i ,i)
+                     (left (%left i) (%left i)))
+                ((> left current-heap-size))
+                (declare (type index i left))
+                (let* ((i-elt (%elt i))
+                       (i-key (funcall keyfun i-elt))
+                       (left-elt (%elt left))
+                       (left-key (funcall keyfun left-elt)))
+                  (multiple-value-bind (large large-elt large-key)
+                      (if (funcall ,',predicate i-key left-key)
+                          (values left left-elt left-key)
+                          (values i i-elt i-key))
+                    (let ((right (%right i)))
+                      (multiple-value-bind (largest largest-elt)
+                          (if (> right current-heap-size)
+                              (values large large-elt)
+                              (let* ((right-elt (%elt right))
+                                     (right-key (funcall keyfun right-elt)))
+                                (if (funcall ,',predicate large-key right-key)
+                                    (values right right-elt)
+                                    (values large large-elt))))
+                        (cond ((= largest i)
+                               (return))
+                              (t
+                               (setf (%elt i) largest-elt
+                                     (%elt largest) i-elt
+                                     i largest)))))))))
+             (%sort-vector (keyfun &optional (vtype 'vector))
+              `(macrolet (;; KLUDGE: In SBCL ca. 0.6.10, I had trouble getting
+                          ;; type inference to propagate all the way
+                          ;; through this tangled mess of
+                          ;; inlining. The TRULY-THE here works
+                          ;; around that. -- WHN
+                          (%elt (i)
+                           `(aref (truly-the ,',vtype ,',',vector)
+                             (%index (+ (%index ,i) start-1)))))
+                (let ((start-1 (1- ,',start)) ; Heaps prefer 1-based addressing.
+                      (current-heap-size (- ,',end ,',start))
+                      (keyfun ,keyfun))
+                  (declare (type (integer -1 #.(1- most-positive-fixnum))
+                                 start-1))
+                  (declare (type index current-heap-size))
+                  (declare (type function keyfun))
+                  (loop for i of-type index
+                        from (ash current-heap-size -1) downto 1 do
+                        (%heapify i))
+                  (loop 
+                   (when (< current-heap-size 2)
+                     (return))
+                   (rotatef (%elt 1) (%elt current-heap-size))
+                   (decf current-heap-size)
+                   (%heapify 1))))))
+    (if (typep ,vector 'simple-vector)
+       ;; (VECTOR T) is worth optimizing for, and SIMPLE-VECTOR is
+       ;; what we get from (VECTOR T) inside WITH-ARRAY-DATA.
+       (if (null ,key)
+           ;; Special-casing the KEY=NIL case lets us avoid some
+           ;; function calls.
+           (%sort-vector #'identity simple-vector)
+           (%sort-vector ,key simple-vector))
+       ;; It's hard to anticipate many speed-critical applications for
+       ;; sorting vector types other than (VECTOR T), so we just lump
+       ;; them all together in one slow dynamically typed mess.
+       (locally
+         (declare (optimize (speed 2) (space 2) (inhibit-warnings 3)))
+         (%sort-vector (or ,key #'identity))))))
 \f
 ;;;; debuggers' little helpers