master: character-string-to-utf8-avx2: shrink the lookup table

stassats via Sbcl-commits <[email protected]>
Newsgroups gmane.lisp.steel-bank.cvs
Message-ID <[email protected]>
The branch "master" has been updated in SBCL:
       via  55d3b2696e4b614dc79c90bd269f7705b1c545c3 (commit)
      from  6c0c0fdc2c09d90286e94ac22bf1632493aee8df (commit)

- Log -----------------------------------------------------------------
commit 55d3b2696e4b614dc79c90bd269f7705b1c545c3
Author: Stas Boukarev <[email protected]>
Date:   Fri Aug 14 04:10:22 2026 +0300

    character-string-to-utf8-avx2: shrink the lookup table
    
    The bit clearing masks can be computed cheaply at runtime.
---
 src/code/x86-64-simd.lisp | 47 +++++++++++++++++++++++++----------------------
 1 file changed, 25 insertions(+), 22 deletions(-)

diff --git a/src/code/x86-64-simd.lisp b/src/code/x86-64-simd.lisp
index 2b24db0fb..fc1801b0b 100644
--- a/src/code/x86-64-simd.lisp
+++ b/src/code/x86-64-simd.lisp
@@ -1545,9 +1545,10 @@
                 (last-newline signed-reg signed-num))
              (flet ((make-full-table ()
                       (let* ((table-size 256)
-                             (row-size 64)
-                             (table (make-array (* table-size row-size) :element-type '(unsigned-byte 8)
-                                                                        :initial-element 0)))
+                             (row-size 32)
+                             (total-size (+ (* table-size row-size) table-size))
+                             (table (make-array total-size :element-type '(unsigned-byte 8)
+                                                           :initial-element 0)))
                         (loop for row below table-size
                               for dest-index = 0
                               do (loop
@@ -1556,23 +1557,18 @@
                                    do (loop for b below bytes
                                             for src-index = (+ (* lane 4) (- bytes 1 b))
                                             for lead-p = (= b 0)
-                                            for and-mask = (if lead-p
-                                                               (case bytes
-                                                                 (1 #x7F) (2 #x1F) (3 #x0F) (4 #x07))
-                                                               #x3F)
                                             for orr-mask = (if lead-p
                                                                (case bytes
                                                                  (1 #x00) (2 #xC0) (3 #xE0) (4 #xF0))
                                                                #x80)
                                             do (setf (aref table (+ (* row row-size) dest-index)) src-index)
-                                               (setf (aref table (+ (* row row-size) 16 dest-index)) and-mask)
-                                               (setf (aref table (+ (* row row-size) 32 dest-index)) orr-mask)
+                                               (setf (aref table (+ (* row row-size) 16 dest-index)) orr-mask)
                                                (incf dest-index)))
+                                 ;; for vpshufb to produce zeros
                                  (loop for i from dest-index below 16
-                                       do (setf (aref table (+ (* row row-size) i)) #xFF)
-                                          (setf (aref table (+ (* row row-size) 16 i)) 0)
-                                          (setf (aref table (+ (* row row-size) 32 i)) 0))
-                                 (setf (aref table (+ (* row row-size) 48)) dest-index))
+                                       do (setf (aref table (+ (* row row-size) i)) #xFF))
+                                 ;; produced bytes
+                                 (setf (aref table (+ (* table-size row-size) row)) dest-index))
                         table)))
                (macrolet ((track-newline (bytes)
                             `(progn
@@ -1682,27 +1678,34 @@
                      ;; Multiplying by 1 + 2^6 + 2^12 + 2^18
                      ;; shifts two bits per byte into the upper byte
                      (inst imul tmp multiplier) ; #x0100040010004000
-                     (inst shr tmp (- 56 6)) ;; shift left 6 for the table entry size
+                     (inst shr tmp (- 56 5)) ;; shift left 5 for the table entry size
 
                      ;; Spread the character to all 4 bytes
+                     ;; For the first byte, the mask depends on if it's a single byte or a continuation byte
+                     ;; t1 has a mask for bytes > 127, choose between #x7f and #x3f based on that.
+                     ;; An ascii character doesn't need to clear anything,
+                     ;; so this either clears nothing or clears ~3f bits.
+                     (inst vpand t1 t1 (register-inline-constant :oword #xFFFFFFC0FFFFFFC0FFFFFFC0FFFFFFC0))
+                     (inst vpandn temp t1 bytes)
+
                      (inst vpslld t1 bytes 6)
                      (inst vpslld t2 bytes 4)
                      (inst vpslld t3 bytes 2)
 
-                     (inst vpand t1 t1 (register-inline-constant :oword #xFF000000FF000000FF000000FF000000))
-                     (inst vpand t2 t2 (register-inline-constant :oword #x00FF000000FF000000FF000000FF0000))
-                     (inst vpand t3 t3 (register-inline-constant :oword #x0000FF000000FF000000FF000000FF00))
-                     (inst vpand bytes bytes (register-inline-constant :oword #x000000FF000000FF000000FF000000FF))
+                     (inst vpand t1 t1 (register-inline-constant :oword #x07000000070000000700000007000000))
+                     (inst vpand t2 t2 (register-inline-constant :oword #x003F0000003F0000003F0000003F0000))
+                     (inst vpand t3 t3 (register-inline-constant :oword #x00003F0000003F0000003F0000003F00))
 
                      (inst vpor t2 t2 t3)
-                     (inst vpor bytes bytes t1)
+                     (inst vpor bytes temp t1)
                      (inst vpor bytes bytes t2)
 
                      ;; Shuffle the bytes into place
                      (inst vpshufb bytes bytes (ea 0 full-table tmp))
-                     (inst vpand bytes bytes (ea 16 full-table tmp))
-                     (inst vpor bytes bytes (ea 32 full-table tmp))
-                     (inst movzx '(:byte :dword) tmp (ea 48 full-table tmp)) ;; number of produced bytes
+
+                     (inst vpor bytes bytes (ea 16 full-table tmp))
+                     (inst shr :dword tmp 5)
+                     (inst mov :byte tmp (ea 8192 full-table tmp)) ;; number of produced bytes
 
                      (inst vmovdqu (ea byte-array) bytes)
 

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


hooks/post-receive
-- 
SBCL
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.