master: Lower :tests for more functions

stassats via Sbcl-commits <[email protected]> Sat, 16 May 2026 00:12:24 +0000
Newsgroups gmane.lisp.steel-bank.cvs
Message-ID <[email protected]>
The branch "master" has been updated in SBCL:
       via  0ede01cab4e55b37e8d79cb8dad1f6bbcb3a0d8f (commit)
      from  02992badc65770f9d7905c7ef213518948c0ab4f (commit)

- Log -----------------------------------------------------------------
commit 0ede01cab4e55b37e8d79cb8dad1f6bbcb3a0d8f
Author: Stas Boukarev <[email protected]>
Date:   Sat May 16 02:18:13 2026 +0300

    Lower :tests for more functions
---
 src/compiler/ir1util.lisp | 19 ++++++++++
 src/compiler/seqtran.lisp | 96 +++++++++++++++++++++++------------------------
 2 files changed, 67 insertions(+), 48 deletions(-)

diff --git a/src/compiler/ir1util.lisp b/src/compiler/ir1util.lisp
index 3f07bdc74..babf5cd3d 100644
--- a/src/compiler/ir1util.lisp
+++ b/src/compiler/ir1util.lisp
@@ -2957,6 +2957,25 @@ is :ANY, the function name is not checked."
        (change-ref-leaf node constant :recklessly t))
       (t
        (insert-ref-before constant node t)))))
+
+(defun change-keyword-value (new-constant keyword value node)
+  (cond (value
+         (let ((ref (lvar-uses value)))
+           (cond ((ref-p ref)
+                  (change-ref-leaf ref new-constant :recklessly t))
+                 (t
+                  (flush-dest value)
+                  (setf (combination-args node)
+                        (subst (insert-ref-before new-constant node)
+                               value
+                               (combination-args node)))))))
+        (t
+         (let ((key (insert-ref-before (find-constant keyword) node))
+               (value (insert-ref-before new-constant node)))
+           (setf (combination-args node)
+                 (append
+                  (combination-args node)
+                  (list key value)))))))
 
 ;;;; leaf hackery
 
diff --git a/src/compiler/seqtran.lisp b/src/compiler/seqtran.lisp
index 88301c778..4e7f88fb9 100644
--- a/src/compiler/seqtran.lisp
+++ b/src/compiler/seqtran.lisp
@@ -703,6 +703,30 @@
                   test)
         test))))
 
+(defun change-test-based-on-item-and-sequence-type (test item sequence key)
+  (let* ((test (if test
+                   (lvar-fun-is test '(eql equal equalp char= char-equal =))
+                   'eql))
+         (test-origin test))
+    (when test
+      (setf test (change-test-based-on-item test (lvar-type item)))
+      (unless (eq test 'eq)
+        (let ((elt (sequence-element-type sequence key)))
+          (setf test (change-test-based-on-item test elt))
+          (cond ((and (memq test '(equalp =))
+                      (csubtypep (lvar-type item) (specifier-type 'integer))
+                      (csubtypep elt (specifier-type 'integer)))
+                 (setf test (if (or (csubtypep (lvar-type item) (specifier-type 'fixnum))
+                                    (csubtypep elt (specifier-type 'fixnum)))
+                                'eq
+                                'eql)))
+                ((and (eq test 'char=)
+                      (csubtypep (lvar-type item) (specifier-type 'character))
+                      (csubtypep elt (specifier-type 'character)))
+                 (setf test 'eq))))))
+    (unless (eq test test-origin)
+      test)))
+
 (macrolet ((def (name &optional if/if-not)
              (let ((basic (symbolicate "%" name))
                    (basic-eq (symbolicate "%" name "-EQ"))
@@ -3098,27 +3122,10 @@
           type))))
 
 (deftransform %find-position ((item sequence from-end start end key test))
-  (let* ((test (lvar-fun-is test '(eql equal equalp char= char-equal =)))
-         (test-origin test))
-    (when test
-      (setf test (change-test-based-on-item test (lvar-type item)))
-      (unless (eq test 'eq)
-        (let ((elt (sequence-element-type sequence key)))
-          (setf test (change-test-based-on-item test elt))
-          (cond ((and (memq test '(equalp =))
-                      (csubtypep (lvar-type item) (specifier-type 'integer))
-                      (csubtypep elt (specifier-type 'integer)))
-                 (setf test (if (or (csubtypep (lvar-type item) (specifier-type 'fixnum))
-                                    (csubtypep elt (specifier-type 'fixnum)))
-                                'eq
-                                'eql)))
-                ((and (eq test 'char=)
-                      (csubtypep (lvar-type item) (specifier-type 'character))
-                      (csubtypep elt (specifier-type 'character)))
-                 (setf test 'eq))))))
-    (if (eq test test-origin)
-        (give-up-ir1-transform)
-        `(%find-position item sequence from-end start end key #',test))))
+  (let ((new-test (change-test-based-on-item-and-sequence-type test item sequence key)))
+    (if new-test
+        `(%find-position item sequence from-end start end key #',new-test)
+        (give-up-ir1-transform))))
 
 ;;; %FIND-POSITION for LIST data can be expanded into %FIND-POSITION-IF
 ;;; without loss of efficiency. (I.e., the optimizer should be able
@@ -3766,27 +3773,6 @@
   (define-find-position find 0)
   (define-find-position position 1))
 
-;;; Lower :test
-(macrolet ((def (fun-name)
-             `(deftransform ,fun-name ((item sequence &key
-                                             from-end start end
-                                             key test test-not)
-                                       (t  &rest t))
-                (macrolet ((maybe-arg (arg &optional (key (keywordicate arg)))
-                             `(and ,arg `(,,key ,',arg))))
-                  (let ((test (and (not test-not)
-                                   (change-test-lvar-based-on-item test item))))
-                    (if test
-                        `(,',fun-name item sequence :test ',test
-                                      ,@(maybe-arg from-end)
-                                      ,@(maybe-arg start)
-                                      ,@(maybe-arg end)
-                                      ,@(maybe-arg key)
-                                      ,@(maybe-arg test-not))
-                        (give-up-ir1-transform)))))))
-  (def find)
-  (def position))
-
 (macrolet ((define-find-position-if (fun-name values-index)
              `(deftransform ,fun-name ((predicate sequence &key
                                                   from-end (start 0)
@@ -4277,7 +4263,14 @@
                        (lvar-annotations value))
                  t))))
       (or (change test-keyword test :test-not)
-          (change test-not-keyword test-not :test)))))
+          (change test-not-keyword test-not :test))
+      nil)))
+
+(defun lower-item-test (node test item sequence key)
+  (let ((new-test (change-test-based-on-item-and-sequence-type test item sequence key)))
+    (when new-test
+      (change-keyword-value (find-global-fun new-test t) :test test node))
+    nil))
 
 (defoptimizers optimizer
     (remove delete count find position
@@ -4285,9 +4278,12 @@
     ((item sequence &rest args &key
            ((test test-keyword))
            ((test-not test-not-keyword))
-           &allow-other-keys))
-  (test-not-complementer test test-keyword test-not test-not-keyword
-                         args))
+           key
+           &allow-other-keys) node)
+  (or (test-not-complementer test test-keyword test-not test-not-keyword
+                             args)
+      (unless test-not
+        (lower-item-test node test item sequence key))))
 
 (defoptimizers optimizer
     (remove-duplicates delete-duplicates
@@ -4304,9 +4300,13 @@
     ((new old sequence &rest args &key
           ((test test-keyword))
           ((test-not test-not-keyword))
-          &allow-other-keys))
+          key
+          &allow-other-keys)
+     node)
   (test-not-complementer test test-keyword test-not test-not-keyword
-                         args))
+                         args)
+  (unless test-not
+    (lower-item-test node test new sequence key)))
 
 (defoptimizers optimizer
     (mismatch search tree-equal

-----------------------------------------------------------------------


hooks/post-receive
-- 
SBCL