master: arm64: use BIC instead of AND if it can load a smaller constant

stassats via Sbcl-commits <[email protected]> Tue, 28 Jul 2026 08:39:40 +0000
Newsgroups gmane.lisp.steel-bank.cvs
Message-ID <[email protected]>
The branch "master" has been updated in SBCL:
       via  ac74dc12c4edf21205cf38ea09454931c062e694 (commit)
      from  34977e04079d689242434132a78066590a04201d (commit)

- Log -----------------------------------------------------------------
commit ac74dc12c4edf21205cf38ea09454931c062e694
Author: Stas Boukarev <[email protected]>
Date:   Tue Jul 28 07:03:51 2026 +0300

    arm64: use BIC instead of AND if it can load a smaller constant
---
 src/compiler/arm64/arith.lisp | 89 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 70 insertions(+), 19 deletions(-)

diff --git a/src/compiler/arm64/arith.lisp b/src/compiler/arm64/arith.lisp
index 5db174dd9..997e2600c 100644
--- a/src/compiler/arm64/arith.lisp
+++ b/src/compiler/arm64/arith.lisp
@@ -217,28 +217,79 @@
   :negative-op sub)
 (define-binop - 4 sub :constant-test abs-add-sub-immediate-p :constant-fixnum-test fixnum-abs-add-sub-immediate-p
   :negative-op add)
-(define-binop logand 2 and
-  :constant-fixnum-test fixnum
-  :constant-fixnum-transform (lambda (x)
-                               (cond ((encode-logical-immediate x)
-                                      x)
-                                     ((let ((tagged (logior x fixnum-tag-mask)))
-                                        (and (encode-logical-immediate tagged)
-                                             tagged)))
-                                     ((and (typep x '(unsigned-byte 32))
-                                           (encode-logical-immediate x 32))
-                                      (setf r (32-bit-reg r))
-                                      x)
-                                     ((and (typep x '(unsigned-byte 32))
-                                           (let ((tagged (logior x fixnum-tag-mask)))
-                                             (when (encode-logical-immediate tagged 32)
-                                               (setf r (32-bit-reg r))
-                                               tagged))))
-                                     (t
-                                      (load-immediate-word tmp-tn x nil t)))))
 (define-binop logior 2 orr)
 (define-binop logxor 2 eor)
 
+(define-vop (fast-logand/fixnum=>fixnum fast-fixnum-binop)
+  (:translate logand)
+  (:generator 2
+    (inst and r x y)))
+
+(define-vop (fast-logand/signed=>signed fast-signed-binop)
+  (:translate logand)
+  (:generator 3
+    (inst and r x y)))
+
+(define-vop (fast-logand/unsigned=>unsigned fast-unsigned-binop)
+  (:translate logand)
+  (:generator 3
+    (inst and r x y)))
+
+(define-vop (fast-logand-c/fixnum=>fixnum fast-fixnum-binop-c)
+  (:arg-types tagged-num (:constant fixnum))
+  (:arg-refs x-ref)
+  (:translate logand)
+  (:generator 1
+    (block nil
+      (let* ((y-untagged y)
+             (y (fixnumize y))
+             (imm
+               (cond ((encode-logical-immediate y) y)
+                     ((let ((tagged (logior y fixnum-tag-mask)))
+                        (and (encode-logical-immediate tagged) tagged)))
+                     ((and (typep y '(unsigned-byte 32)) (encode-logical-immediate y 32)) (setf r (32-bit-reg r)) y)
+                     ((and (typep y '(unsigned-byte 32))
+                           (let ((tagged (logior y fixnum-tag-mask)))
+                             (when (encode-logical-immediate tagged 32) (setf r (32-bit-reg r)) tagged))))
+                     ((load-immediate-word tmp-tn y t t))
+                     ;; Use BIC if the inverted constant can be loaded with one instruction
+                     ((let* ((width (or (sb-c::unsigned-type-width (tn-ref-type x-ref))
+                                        n-fixnum-bits))
+                             (inverted (ash (ldb (byte width 0) (lognot y-untagged)) n-fixnum-tag-bits)))
+                        (when (load-immediate-word tmp-tn inverted t t)
+                          (inst bic r x tmp-tn)
+                          (return))))
+                     ((load-immediate-word tmp-tn y nil t)))))
+        (inst and r x imm)))))
+
+(define-vop (fast-logand-c/signed=>signed fast-signed-binop-c)
+  (:translate logand)
+  (:arg-refs x-ref)
+  (:arg-types signed-num (:constant integer))
+  (:generator 2
+    (block nil
+      (let* ((imm
+               (cond ((encode-logical-immediate y) y)
+                     ((and (typep y '(unsigned-byte 32)) (encode-logical-immediate y 32)) (setf r (32-bit-reg r)) y)
+                     ((load-immediate-word tmp-tn y t))
+                     ;; Use BIC if the inverted constant can be loaded with one instruction
+                     ((let* ((width (or (sb-c::unsigned-type-width (tn-ref-type x-ref))
+                                        64))
+                             (inverted (ldb (byte width 0) (lognot y))))
+                        (when (load-immediate-word tmp-tn inverted t)
+                          (inst bic r x tmp-tn)
+                          (return))))
+                     ((load-immediate-word tmp-tn y nil)))))
+        (inst and r x imm)))))
+
+(define-vop (fast-logand-c/unsigned=>unsigned fast-signed-binop-c)
+  (:translate logand)
+  (:args (x :scs (unsigned-reg)))
+  (:info y)
+  (:results (r :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:arg-types unsigned-num (:constant (satisfies encode-logical-immediate))))
+
 (define-vop (fast-/unsigned-signed fast-safe-arith-op)
   (:translate -)
   (:args (x :scs (unsigned-reg signed-reg))

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


hooks/post-receive
-- 
SBCL