master: NEON simd-copy-utf8-to-base-string
stassats via Sbcl-commits <[email protected]> Tue, 30 Jun 2026 01:24:51 +0000
| Newsgroups | gmane.lisp.steel-bank.cvs |
|---|---|
| Message-ID | <[email protected]> |
The branch "master" has been updated in SBCL:
via 55322d716c6f952168ba59f3bc53b133e074d7c3 (commit)
from 3f79152d61de759a0da552e62e7a9287ba567b76 (commit)
- Log -----------------------------------------------------------------
commit 55322d716c6f952168ba59f3bc53b133e074d7c3
Author: Stas Boukarev <[email protected]>
Date: Tue Jun 30 00:27:18 2026 +0300
NEON simd-copy-utf8-to-base-string
---
src/code/arm64-simd.lisp | 53 +++++++++++++++++++++++++++++-
src/code/external-formats/enc-basic.lisp | 56 ++++++++++++++++++--------------
2 files changed, 84 insertions(+), 25 deletions(-)
diff --git a/src/code/arm64-simd.lisp b/src/code/arm64-simd.lisp
index 907bdf50d..63df91b18 100644
--- a/src/code/arm64-simd.lisp
+++ b/src/code/arm64-simd.lisp
@@ -62,7 +62,7 @@
;;; This doesn't prevent the var from going to the stack, but none of
;;; the routines should do that.
(defmacro with-pinned-objects-in-registers (vars &body body)
- `(multiple-value-prog1 ,@body
+ `(multiple-value-prog1 (progn ,@body)
,@(loop for var in vars
collect `(touch-object ,var))))
@@ -630,6 +630,57 @@
do (setf (aref string i)
(code-char (sap-ref-8 sap i))))))
+(defun simd-copy-character-string-to-utf8-byte-array (byte-array string length)
+ (declare (index length)
+ (simple-character-string string)
+ ((simple-array (unsigned-byte 8) (*)) byte-array)
+ (optimize speed (safety 0)))
+ (with-pinned-objects-in-registers (string byte-array)
+ (inline-vop (((byte-array sap-reg t) (vector-sap byte-array))
+ ((32-bit-array sap-reg t) (vector-sap string))
+ ((n unsigned-reg) (logand (+ (* length 4) 15) -16))
+ ((bytes complex-double-reg t :offset 1))
+ ((bytes2 complex-double-reg t :offset 2))
+ ((bytes3 complex-double-reg t :offset 3))
+ ((bytes4 complex-double-reg t :offset 4)))
+ ()
+ (inst cmp n 64)
+ (inst b :lt TAIL)
+
+ LOOP
+
+ (inst ld1 (list bytes bytes2 bytes3 bytes4) (@ 32-bit-array 64 :post-index) :4s)
+
+ (inst uzp1 bytes2 bytes bytes2 :8h)
+ (inst uzp1 bytes4 bytes3 bytes4 :8h)
+ (inst uzp1 bytes4 bytes2 bytes4 :16b)
+ (inst str bytes4 (@ byte-array 16 :post-index))
+ (inst sub n n 64)
+ (inst cmp n 64)
+ (inst b :ge LOOP)
+
+ TAIL
+ (inst cbz n DONE)
+ (inst movi bytes2 0 :2d)
+ (inst movi bytes3 0 :2d)
+
+ (inst tbz n 5 ONE)
+ (inst tbz n 4 TWO)
+
+ (inst ldr bytes3 (@ 32-bit-array 32))
+ (inst uzp1 bytes3 bytes3 bytes2 :8h)
+ TWO
+ (inst ldr bytes2 (@ 32-bit-array 16))
+ ONE
+ (inst ldr bytes (@ 32-bit-array))
+
+ (inst uzp1 bytes2 bytes bytes2 :8h)
+ (inst uzp1 bytes3 bytes2 bytes3 :16b)
+ (inst str bytes3 (@ byte-array))
+
+ DONE))
+ byte-array)
+
(defun simd-copy-utf8-to-base-string (start end string ibuf)
(declare (type index start end)
(optimize speed (safety 0)))
diff --git a/src/code/external-formats/enc-basic.lisp b/src/code/external-formats/enc-basic.lisp
index 7903b7ade..1db4014b5 100644
--- a/src/code/external-formats/enc-basic.lisp
+++ b/src/code/external-formats/enc-basic.lisp
@@ -1670,38 +1670,46 @@
(incf index)))
(values length nil)))))
+#+(and 64-bit sb-unicode (not arm64))
+(defun sb-vm::simd-copy-character-string-to-utf8-byte-array (byte-array string length)
+ (declare (index length)
+ (simple-character-string string)
+ ((simple-array (unsigned-byte 8) (*)) byte-array)
+ (optimize speed (safety 0)))
+ (let ((byte-index 0))
+ (declare (index byte-index))
+ ;; SWAR ASCII
+ #+64-bit
+ (with-pinned-objects (byte-array)
+ (let ((sap (vector-sap byte-array))
+ (word-length (truncate length 2))
+ (index 0))
+ (declare (index index))
+ (loop until (>= index word-length)
+ do (let* ((word (%vector-raw-bits string index))
+ (a (ldb (byte 8 0) word))
+ (b (ash word -24)))
+ (setf (sap-ref-16 sap (* index 2))
+ (logior a b)))
+
+ (incf index)
+ (incf byte-index 2))))
+ (loop for i from byte-index below length
+ do (setf (aref byte-array i)
+ (logand (char-code (aref string i)) #xFF)))))
+
(defun output-to-c-string/utf-8/lf (string)
(declare (type simple-string string)
(optimize speed (safety 0)))
- (cond ((simple-base-string-p string) string)
+ (cond ((base-string-p string) string)
(t
(multiple-value-bind (buffer-length ascii-only) (simd-character-string-utf8-length string)
(unless buffer-length
(check-utf8-encoding string))
- (let* ((buffer (make-array (1+ buffer-length) :element-type '(unsigned-byte 8)
- :initial-element 0)))
+ (let ((buffer (make-array (1+ buffer-length) :element-type '(unsigned-byte 8)
+ :initial-element 0)))
(cond (ascii-only
- (let ((byte-index 0))
- (declare (index byte-index))
- ;; SWAR ASCII
- #+64-bit
- (with-pinned-objects (buffer)
- (let ((sap (vector-sap buffer))
- (word-length (truncate buffer-length 2))
- (index 0))
- (declare (index index))
- (loop until (>= index word-length)
- do (let* ((word (%vector-raw-bits string index))
- (a (ldb (byte 8 0) word))
- (b (ash word -24)))
- (setf (sap-ref-16 sap (* index 2))
- (logior a b)))
-
- (incf index)
- (incf byte-index 2))))
- (loop for i from byte-index below buffer-length
- do (setf (aref buffer i)
- (logand (char-code (aref string i)) #xFF)))))
+ (sb-vm::simd-copy-character-string-to-utf8-byte-array buffer string buffer-length))
(t
(let ((index 0))
(declare (index index))
-----------------------------------------------------------------------
hooks/post-receive
--
SBCL