teach IR1-TRANSFORM-TYPE-PREDICATE about alien types
authorNikodemus Siivola <nikodemus@random-state.net>
Fri, 20 Apr 2012 14:04:32 +0000 (17:04 +0300)
committerNikodemus Siivola <nikodemus@random-state.net>
Fri, 20 Apr 2012 16:13:56 +0000 (19:13 +0300)
  Convert to ALIEN-VALUE-TYPEP (new function). Avoids both the need to do the
  whole type parsing rigamarole at runtime, and checking for lisp-rep-type.

  Need to do this as late in the game as possible, because after we convert to
  ALIEN-VALUE-TYPEP, the rest of the system stops understanding it as a type
  test. (We really should have some sort of annotation for this sort of stuff,
  so we could convert whenever.)

NEWS
package-data-list.lisp-expr
src/code/target-alieneval.lisp
src/compiler/typetran.lisp

diff --git a/NEWS b/NEWS
index 92a7af6..75b9204 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ changes relative to sbcl-1.0.56:
     called with too many arguments.
   * optimization: fewer uses of full calls to signed modular functions.
     (lp#903821)
+  * optimization: typechecking alien values is typically 5 x faster.
   * bug fix: fixed disassembly of some SSE instructions on x86-64.
   * bug fix: SB-SIMPLE-STREAMS signals an error for bogus :CLASS arguments in
     OPEN. (lp#969352, thanks to Kambiz Darabi)
index 2ef025b..a8c7825 100644 (file)
@@ -97,7 +97,9 @@ of SBCL which maintained the CMU-CL-style split into two packages.)"
                "ALIEN-SINGLE-FLOAT-TYPE-P" "ALIEN-SUBTYPE-P" "ALIEN-TYPE"
                "ALIEN-TYPE-=" "ALIEN-TYPE-ALIGNMENT" "ALIEN-TYPE-BITS"
                "ALIEN-TYPE-P" "ALIEN-TYPEP"
-               "ALIEN-VALUE" "ALIEN-VALUE-TYPE"
+               "ALIEN-VALUE"
+               "ALIEN-VALUE-TYPE"
+               "ALIEN-VALUE-TYPEP"
                "ALIEN-VALUE-SAP" "ALIEN-VALUE-P"
                "ALIEN-VALUES-TYPE" "ALIEN-VALUES-TYPE-P"
                "ALIEN-VALUES-TYPE-VALUES" "ALIGN-OFFSET" "ALIEN-VOID-TYPE-P"
index aa7922f..a446c87 100644 (file)
@@ -814,6 +814,10 @@ null byte.
         (and (alien-value-p object)
              (alien-subtype-p (alien-value-type object) type)))))
 
+(defun alien-value-typep (object type)
+  (when (alien-value-p object)
+    (alien-subtype-p (alien-value-type object) type)))
+
 ;;;; ALIEN CALLBACKS
 ;;;;
 ;;;; See "Foreign Linkage / Callbacks" in the SBCL Internals manual.
index 3c000d5..aeb9a7b 100644 (file)
 ;;; If the lvar OBJECT definitely is or isn't of the specified
 ;;; type, then return T or NIL as appropriate. Otherwise quietly
 ;;; GIVE-UP-IR1-TRANSFORM.
-(defun ir1-transform-type-predicate (object type)
+(defun ir1-transform-type-predicate (object type node)
   (declare (type lvar object) (type ctype type))
   (let ((otype (lvar-type object)))
-    (cond ((not (types-equal-or-intersect otype type))
-           nil)
-          ((csubtypep otype type)
-           t)
-          ((eq type *empty-type*)
-           nil)
-          (t
-           (let ((intersect (type-intersection2 type otype)))
-             (unless intersect
-               (give-up-ir1-transform))
-             (multiple-value-bind (constantp value)
-                 (type-singleton-p intersect)
-               (if constantp
-                   `(eql object ',value)
-                   (give-up-ir1-transform))))))))
+    (flet ((tricky ()
+             (cond ((typep type 'alien-type-type)
+                    ;; We don't transform alien type tests until here, because
+                    ;; once we do that the rest of the type system can no longer
+                    ;; reason about them properly -- so we'd miss out on type
+                    ;; derivation, etc.
+                    (delay-ir1-transform node :optimize)
+                    (let ((alien-type (alien-type-type-alien-type type)))
+                      ;; If it's a lisp-rep-type, the CTYPE should be one already.
+                      (aver (not (compute-lisp-rep-type alien-type)))
+                      `(sb!alien::alien-value-typep object ',alien-type)))
+                   (t
+                    (give-up-ir1-transform)))))
+      (cond ((not (types-equal-or-intersect otype type))
+            nil)
+           ((csubtypep otype type)
+            t)
+           ((eq type *empty-type*)
+            nil)
+           (t
+            (let ((intersect (type-intersection2 type otype)))
+              (unless intersect
+                (tricky))
+              (multiple-value-bind (constantp value)
+                  (type-singleton-p intersect)
+                (if constantp
+                    `(eql object ',value)
+                    (tricky)))))))))
 
 ;;; Flush %TYPEP tests whose result is known at compile time.
-(deftransform %typep ((object type))
+(deftransform %typep ((object type) * * :node node)
   (unless (constant-lvar-p type)
     (give-up-ir1-transform))
   (ir1-transform-type-predicate
    object
-   (ir1-transform-specifier-type (lvar-value type))))
+   (ir1-transform-specifier-type (lvar-value type))
+   node))
 
 ;;; This is the IR1 transform for simple type predicates. It checks
 ;;; whether the single argument is known to (not) be of the
                            (basic-combination-fun node))))
                         *backend-predicate-types*)))
     (aver ctype)
-    (ir1-transform-type-predicate object ctype)))
+    (ir1-transform-type-predicate object ctype node)))
 
 ;;; If FIND-CLASSOID is called on a constant class, locate the
 ;;; CLASSOID-CELL at load time.