Re: master: arm64: implement %vector-cas-pair (for Armv8.1-A or later)

Stas Boukarev <[email protected]>
Newsgroups gmane.lisp.steel-bank.cvs,gmane.lisp.steel-bank.devel
Message-ID <CAF63=10w6-fOXeULfVZAoR6whti=phMFr39vCmZ1XUQJdqWKrw@mail.gmail.com>
        "The file #P"/proc/cpuinfo" does not exist: No such file or directory"

On Thu, Jan 8, 2026 at 11:24 PM snuglas via Sbcl-commits
<[email protected]> wrote:
>
> The branch "master" has been updated in SBCL:
>        via  e0c54aa0968bea23f2e0044f76f501525adcd625 (commit)
>       from  3f57e70440ae3d6233b674556b9540c0ad89c0d7 (commit)
>
> - Log -----------------------------------------------------------------
> commit e0c54aa0968bea23f2e0044f76f501525adcd625
> Author: Douglas Katzman <[email protected]>
> Date:   Thu Jan 8 20:12:06 2026 +0000
>
>     arm64: implement %vector-cas-pair (for Armv8.1-A or later)
> ---
>  make-target-2-load.lisp            |  7 ++++---
>  src/code/stubs.lisp                |  3 ++-
>  src/compiler/arm64/insts.lisp      | 21 +++++++++++++++++++++
>  src/compiler/arm64/memory.lisp     | 32 ++++++++++++++++++++++++++++++++
>  src/compiler/generic/vm-fndb.lisp  |  3 +++
>  src/compiler/x86-64/cell.lisp      |  2 +-
>  src/compiler/x86/cell.lisp         |  2 +-
>  tests/compare-and-swap.impure.lisp | 31 +++++++++++++++++++++----------
>  8 files changed, 85 insertions(+), 16 deletions(-)
>
> diff --git a/make-target-2-load.lisp b/make-target-2-load.lisp
> index 393312193..270cdf3e7 100644
> --- a/make-target-2-load.lisp
> +++ b/make-target-2-load.lisp
> @@ -436,9 +436,10 @@ Please check that all strings which were not recognizable to the compiler
>                              ;; need this for defining a vop which
>                              ;; tests the x86-64 allocation profiler
>                              sb-vm::pseudo-atomic
> -                            ,@(or #+(or x86 x86-64) '(sb-vm::%vector-cas-pair
> -                                                      sb-vm::%instance-cas-pair
> -                                                      sb-vm::%cons-cas-pair))
> +                            ,@(or #+(or arm64 x86 x86-64)
> +                                  '(sb-vm::%vector-cas-pair
> +                                    sb-vm::%instance-cas-pair
> +                                    sb-vm::%cons-cas-pair))
>                              ;; Naughty outside-world code uses these.
>                              #+x86-64 sb-vm::reg-in-size))
>             (let ((s (string symbol))) (and (search "THREAD-" s) (search "-SLOT" s)))
> diff --git a/src/code/stubs.lisp b/src/code/stubs.lisp
> index 0a6eb0a7a..12bc63cc7 100644
> --- a/src/code/stubs.lisp
> +++ b/src/code/stubs.lisp
> @@ -139,9 +139,10 @@
>    #+compare-and-swap-vops
>    (def* (%array-atomic-incf/word (array index diff))
>          (%raw-instance-atomic-incf/word (instance index diff)))
> +  #+(or arm64 x86 x86-64)
> +  (def* (sb-vm::%vector-cas-pair (vector index old1 old2 new1 new2)))
>    #+(or x86 x86-64)
>    (def* (sb-vm::%cpu-identification (eax ecx))
> -        (sb-vm::%vector-cas-pair (vector index old1 old2 new1 new2))
>          (sb-vm::%instance-cas-pair (instance index old1 old2 new1 new2))
>          (sb-vm::%cons-cas-pair (cons old1 old2 new1 new2)))
>
> diff --git a/src/compiler/arm64/insts.lisp b/src/compiler/arm64/insts.lisp
> index f498124df..721858dce 100644
> --- a/src/compiler/arm64/insts.lisp
> +++ b/src/compiler/arm64/insts.lisp
> @@ -1728,6 +1728,27 @@
>  (def-casb casalh 1 1 1)
>  (def-casb caslh 1 1 0)
>
> +;;;  32-bit CASP   (sz == 0 && L == 0 && o0 == 0)
> +;;;  32-bit CASPA  (sz == 0 && L == 1 && o0 == 0)
> +;;;  32-bit CASPAL (sz == 0 && L == 1 && o0 == 1)
> +;;;  32-bit CASPL  (sz == 0 && L == 0 && o0 == 1)
> +;;;  64-bit CASP   (sz == 1 && L == 0 && o0 == 0)
> +;;;  64-bit CASPA  (sz == 1 && L == 1 && o0 == 0)
> +;;;  64-bit CASPAL (sz == 1 && L == 1 && o0 == 1)
> +;;;  64-bit CASPL  (sz == 1 && L == 0 && o0 == 1)
> +
> +;;; Given that memory ordering semantics are completely unknown to the compiler,
> +;;; the full set of CASP instructions are not terribly interesting for us.
> +;;; The strongest barrier is enough.
> +(define-instruction caspal (segment rs rt rn) ; CAS pair acquire + release
> +  (:printer cas ((size1 0) (o2 0) (L 1) (o0 1))
> +            '(:name :tab rs ", " rt ", [" rn "]"))
> +  (:emitter
> +   (emit-ldr-str-exclusive segment #b01 0 1 1
> +                           (gpr-offset rs)
> +                           1 31
> +                           (gpr-offset rn)
> +                           (gpr-offset rt))))
>  ;;;
>
>  (def-emitter ldatomic
> diff --git a/src/compiler/arm64/memory.lisp b/src/compiler/arm64/memory.lisp
> index 91113d946..e05159f00 100644
> --- a/src/compiler/arm64/memory.lisp
> +++ b/src/compiler/arm64/memory.lisp
> @@ -135,6 +135,38 @@
>      (move result old-value)
>      (inst casal result new-value lip)))
>
> +(define-vop (%vector-cas-pair)
> +  (:translate %vector-cas-pair)
> +  (:policy :fast-safe)
> +  (:args (object :scs (descriptor-reg) :to (:result 0))
> +         (index :scs (any-reg))
> +         (old1 :scs (any-reg descriptor-reg))
> +         (old2 :scs (any-reg descriptor-reg))
> +         (new1 :scs (any-reg descriptor-reg))
> +         (new2 :scs (any-reg descriptor-reg)))
> +  (:arg-types * tagged-num * * * *)
> +  (:temporary (:sc descriptor-reg :offset r0-offset :from (:argument 2) :to (:result 0)) oldpair-first)
> +  (:temporary (:sc descriptor-reg :offset r1-offset :from (:argument 3) :to (:result 1)) oldpair-second)
> +  (:temporary (:sc descriptor-reg :offset r2-offset :from (:argument 4) :to (:result 0)) newpair-first)
> +  (:temporary (:sc descriptor-reg :offset r3-offset :from (:argument 5) :to (:result 0)) newpair-second)
> +  (:temporary (:sc unsigned-reg) tmp)
> +  (:temporary (:sc non-descriptor-reg) lip)
> +  (:results (result1 :scs (any-reg descriptor-reg))
> +            (result2 :scs (any-reg descriptor-reg)))
> +  (:result-types * *)
> +  (:policy :fast-safe)
> +  (:generator 3
> +    (inst add lip object (lsl index (- word-shift n-fixnum-tag-bits)))
> +    (inst add-sub lip lip (- (* vector-data-offset n-word-bytes) other-pointer-lowtag))
> +    (emit-gengc-barrier object lip tmp t)
> +    (move oldpair-first old1)
> +    (move oldpair-second old2)
> +    (move newpair-first new1)
> +    (move newpair-second new2)
> +    (inst caspal oldpair-first newpair-first lip)
> +    (move result1 oldpair-first)
> +    (move result2 oldpair-second)))
> +
>  #+sb-thread
>  (define-vop (set-instance-hashed-return-address)
>    (:args (object :scs (descriptor-reg)))
> diff --git a/src/compiler/generic/vm-fndb.lisp b/src/compiler/generic/vm-fndb.lisp
> index fa2a86d8e..3564e8ed3 100644
> --- a/src/compiler/generic/vm-fndb.lisp
> +++ b/src/compiler/generic/vm-fndb.lisp
> @@ -251,6 +251,9 @@
>    sb-vm:signed-word ())
>  (defknown %raw-instance-xchg/word (instance index sb-vm:word) sb-vm:word ())
>
> +;; vector, index, old1, old2, new1, new2 -> old1, old2
> +(defknown sb-vm::%vector-cas-pair (simple-vector index t t t t) (values t t))
> +
>  (macrolet ((define-raw-slot-defknowns ()
>               `(progn
>                  ,@(map 'list
> diff --git a/src/compiler/x86-64/cell.lisp b/src/compiler/x86-64/cell.lisp
> index 70a1e5c51..caf438b5a 100644
> --- a/src/compiler/x86-64/cell.lisp
> +++ b/src/compiler/x86-64/cell.lisp
> @@ -719,7 +719,6 @@
>  ;;;;
>
>  (defknown %cons-cas-pair (cons t t t t) (values t t))
> -(defknown %vector-cas-pair (simple-vector index t t t t) (values t t))
>  ;; %INSTANCE-CAS-PAIR only operates on tagged slots (for now)
>  (defknown %instance-cas-pair (instance index t t t t) (values t t))
>
> @@ -761,6 +760,7 @@
>            ;; this is sufficiently confusing that I don't want to try reusing
>            ;; one of the other declared temps as the EA for the store barrier.
>            (:temporary (:sc unsigned-reg) temp)
> +          ;; FIXME: these operand lifetimes are wrong for INDEXEDP = NIL.
>            (:temporary (:sc unsigned-reg :offset rax-offset
>                         :from (:argument 2) :to (:result 0)) eax)
>            (:temporary (:sc unsigned-reg :offset rdx-offset
> diff --git a/src/compiler/x86/cell.lisp b/src/compiler/x86/cell.lisp
> index ca3a36f7e..3b8e93747 100644
> --- a/src/compiler/x86/cell.lisp
> +++ b/src/compiler/x86/cell.lisp
> @@ -655,7 +655,6 @@
>  ;;;;
>
>  (defknown %cons-cas-pair (cons t t t t) (values t t))
> -(defknown %vector-cas-pair (simple-vector index t t t t) (values t t))
>  ;; %INSTANCE-CAS-PAIR only operates on tagged slots (for now)
>  (defknown %instance-cas-pair (instance index t t t t) (values t t))
>
> @@ -690,6 +689,7 @@
>                   (new-hi :scs (descriptor-reg any-reg) :target ecx))
>            (:results (result-lo :scs (descriptor-reg any-reg))
>                      (result-hi :scs (descriptor-reg any-reg)))
> +          ;; FIXME: these operand lifetimes are wrong for INDEX-ARG = NIL
>            (:temporary (:sc unsigned-reg :offset eax-offset
>                         :from (:argument 2) :to (:result 0)) eax)
>            (:temporary (:sc unsigned-reg :offset edx-offset
> diff --git a/tests/compare-and-swap.impure.lisp b/tests/compare-and-swap.impure.lisp
> index 8fe1c2ad1..f1dbd8c40 100644
> --- a/tests/compare-and-swap.impure.lisp
> +++ b/tests/compare-and-swap.impure.lisp
> @@ -579,6 +579,7 @@
>      (%instance-cas-pair inst ind old1 old2 new1 new2))
>
>    (defun test-wide-cmpxchg ()
> +    #-arm64
>      (let ((x (cons 'a 'b)))
>        (multiple-value-bind (old1 old2) (test-a-cons x 'a 'b 'foo 'bar)
>          (assert (and (eq old1 'a) (eq old2 'b) (equal x '(foo . bar)))))
> @@ -591,6 +592,7 @@
>        (multiple-value-bind (old1 old2) (test-a-vect x 2 nil nil 'foo 'bar)
>          (assert (and (null old1) (null old2) (equalp x #(nil nil foo bar nil nil))))))
>
> +    #-arm64
>      ;; Same remark applies - just check that the offset to the slot is right.
>      (let ((s (make-my-struct :three 'the :four 'floor)))
>        ;; in slots 3 and 4 put your bootee (a baby shoe, i.e.) on the floor
> @@ -600,19 +602,28 @@
>                       (eq (my-struct-four s) 'bootee)))))
>      t))
>
> -(test-util:with-test (:name :wide-compare-and-exchange
> -                      :skipped-on (not (or :x86 :x86-64)))
> +(defun should-test-dblcas ()
> +  #+arm64
> +  (with-open-file (f "/proc/cpuinfo")
> +    (loop repeat 4
> +          thereis (let ((line (read-line f)))
> +                    (and (search "Features" line) (search " atomics " line)))))
> +  #+(or x86 x86-64)
>    (multiple-value-bind (a b c d) (%cpu-identification 0 0)
>      (declare (ignore b c d))
>      ;; paranoidly check for whether we can execute function ID 1
> -    (or (and (>= a 1) ; the highest function ID
> -             (multiple-value-bind (a b c d) (%cpu-identification 1 0)
> -               (declare (ignore a b) (ignorable c d))
> -               ;; paranoidly check for CMPXCHGxB presence
> -               ;; constants from Table 3-20 and 3-21 of Intel manual
> -               (and #+x86(logbitp 8 d) #+x86-64(logbitp 13 c)
> -                    (test-wide-cmpxchg))))
> -        (format t "Double-width compare-and-swap NOT TESTED~%"))))
> +    (and (>= a 1) ; the highest function ID
> +         (multiple-value-bind (a b c d) (%cpu-identification 1 0)
> +           (declare (ignore a b) (ignorable c d))
> +           ;; paranoidly check for CMPXCHGxB presence
> +           ;; constants from Table 3-20 and 3-21 of Intel manual
> +           (and #+x86 (logbitp 8 d) #+x86-64 (logbitp 13 c))))))
> +
> +(test-util:with-test (:name :wide-compare-and-exchange
> +                      :skipped-on (not (or :arm64 :x86 :x86-64)))
> +  (if (should-test-dblcas)
> +      (test-wide-cmpxchg)
> +      (format t "Double-width compare-and-swap NOT TESTED~%")))
>
>  (test-util:with-test (:name :cas-sap-ref-smoke-test
>                              :fails-on :riscv ; unsigned-32-bit gets the wrong answer
>
> -----------------------------------------------------------------------
>
>
> hooks/post-receive
> --
> SBCL
>
>
> _______________________________________________
> Sbcl-commits mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/sbcl-commits


_______________________________________________
Sbcl-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sbcl-commits
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.