0.8.21.39: implement optimization #25
authorNikodemus Siivola <nikodemus@random-state.net>
Thu, 14 Apr 2005 14:05:20 +0000 (14:05 +0000)
committerNikodemus Siivola <nikodemus@random-state.net>
Thu, 14 Apr 2005 14:05:20 +0000 (14:05 +0000)
 * transform EQL to EQ when at least other argument is known to be
    (OR FIXNUM (NOT NUMBER)).

NEWS
OPTIMIZATIONS
src/compiler/srctran.lisp
tests/compiler.impure.lisp
version.lisp-expr

diff --git a/NEWS b/NEWS
index a5f3458..f82dc62 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,8 @@ changes in sbcl-0.8.22 relative to sbcl-0.8.21:
   * 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.
index f17f2ee..d8d018f 100644 (file)
@@ -204,20 +204,6 @@ a. Iterations on &REST lists, returning them as VALUES could be
    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:
 
index 44930ba..4b1f05a 100644 (file)
 ;;; -- 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
index 5baf7d1..57e9636 100644 (file)
 ;;; 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)
index ff0ac14..d7e19e5 100644 (file)
@@ -17,4 +17,4 @@
 ;;; 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"