* optimization: REPLACE on declared (UNSIGNED-BYTE 8) vectors, as well
as other specialized array types, is much faster. SUBSEQ and
COPY-SEQ on such arrays have also been sped up.
+ * optimization: EQL is now more efficient when at least other argument
+ is known to be of type (OR FIXNUM (NOT NUMBER)).
* fixed bug: the runtime is now less vulnerable to changes in the
size of the SBCL object on OS X, and virtual memory is reserved for
all spaces that need to be at a fixed address.
rewritten with &MORE vectors.
b. Implement local unknown-values mv-call (useful for fast type checking).
--------------------------------------------------------------------------------
-#25
-EQL is implemented generically in situations where this isn't necessary.
-
-(defun f (x y)
- (declare (type (or symbol fixnum) x)
- (optimize speed (safety 0) (debug 0)))
- (eql x y))
-
-SUBTYPEP is smart enough to determine that this type is a subtype
-of (and (or (not number) fixnum) (not character))
-
-This sitation where the type is (OR NULL FIXNUM) comes up
-in cl-bench, for example in the value returned by POSITION.
---------------------------------------------------------------------------------
#26
SBCL cannot derive upper bound for I and uses generic arithmetic here:
;;; -- 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.
-;;; -- If either arg is definitely not a number, then we can compare
-;;; with EQ.
+;;; -- If either arg is definitely not a number, or a fixnum, then we
+;;; can compare with EQ.
;;; -- Otherwise, we try to put the arg we know more about second. If X
;;; is constant then we put it second. If X is a subtype of Y, we put
;;; 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 efficiency note.
(deftransform eql ((x y) * *)
"convert to simpler equality predicate"
(let ((x-type (lvar-type x))
(y-type (lvar-type y))
- (char-type (specifier-type 'character))
- (number-type (specifier-type 'number)))
- (cond
- ((same-leaf-ref-p x y) t)
- ((not (types-equal-or-intersect x-type y-type))
- nil)
- ((and (csubtypep x-type char-type)
- (csubtypep y-type char-type))
- '(char= x y))
- ((or (not (types-equal-or-intersect x-type number-type))
- (not (types-equal-or-intersect y-type number-type)))
- '(eq x y))
- ((and (not (constant-lvar-p y))
- (or (constant-lvar-p x)
- (and (csubtypep x-type y-type)
- (not (csubtypep y-type x-type)))))
- '(eql y x))
- (t
- (give-up-ir1-transform)))))
+ (char-type (specifier-type 'character)))
+ (flet ((simple-type-p (type)
+ (csubtypep type (specifier-type '(or fixnum (not number))))))
+ (cond
+ ((same-leaf-ref-p x y) t)
+ ((not (types-equal-or-intersect x-type y-type))
+ nil)
+ ((and (csubtypep x-type char-type)
+ (csubtypep y-type char-type))
+ '(char= x y))
+ ((or (simple-type-p x-type) (simple-type-p y-type))
+ '(eq x y))
+ ((and (not (constant-lvar-p y))
+ (or (constant-lvar-p x)
+ (and (csubtypep x-type y-type)
+ (not (csubtypep y-type x-type)))))
+ '(eql y x))
+ (t
+ (give-up-ir1-transform))))))
;;; similarly to the EQL transform above, we attempt to constant-fold
;;; or convert to a simpler predicate: mostly we have to be careful
;;; bug 211e: bogus style warning from duplicated keyword argument to
;;; a local function.
(handler-bind ((style-warning #'error))
- (let ((f (compile nil '(lambda () (flet ((foo (&key y) (list y)))
- (list (foo :y 1 :y 2)))))))
+ (let ((f (compile nil '(lambda ()
+ (flet ((foo (&key y) (list y)))
+ (list (foo :y 1 :y 2)))))))
(assert (equal '((1)) (funcall f)))))
+;;; check that EQL is optimized when other argument is (OR SYMBOL FIXNUM).
+(handler-bind ((compiler-note #'error))
+ (let ((f1 (compile nil '(lambda (x1 y1)
+ (declare (type (or symbol fixnum) x1)
+ (optimize speed))
+ (eql x1 y1))))
+ (f2 (compile nil '(lambda (x2 y2)
+ (declare (type (or symbol fixnum) y2)
+ (optimize speed))
+ (eql x2 y2)))))
+ (let ((fix (random most-positive-fixnum))
+ (sym (gensym))
+ (e-count 0))
+ (assert (funcall f1 fix fix))
+ (assert (funcall f2 fix fix))
+ (assert (funcall f1 sym sym))
+ (assert (funcall f2 sym sym))
+ (handler-bind ((type-error (lambda (c)
+ (incf e-count)
+ (continue c))))
+ (flet ((test (f x y)
+ (with-simple-restart (continue "continue with next test")
+ (funcall f x y)
+ (error "fell through with (~S ~S ~S)" f x y))))
+ (test f1 "oops" 42)
+ (test f1 (1+ most-positive-fixnum) 42)
+ (test f2 42 "oops")
+ (test f2 42 (1+ most-positive-fixnum))))
+ (assert (= e-count 4)))))
+
;;; success
(quit :unix-status 104)
;;; checkins which aren't released. (And occasionally for internal
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"0.8.21.38"
+"0.8.21.39"