master: x86-64: Rearrange CAS vops for SYMBOL-[GLOBAL-]VALUE

snuglas via Sbcl-commits <[email protected]>
Newsgroups gmane.lisp.steel-bank.cvs
Message-ID <[email protected]>
The branch "master" has been updated in SBCL:
       via  8e6ef6fb951369fa974d20c779066e83cff7da7e (commit)
      from  002e5c99e4ee0a1ce166fcd8047a61c2d790e3bc (commit)

- Log -----------------------------------------------------------------
commit 8e6ef6fb951369fa974d20c779066e83cff7da7e
Author: Douglas Katzman <[email protected]>
Date:   Thu Apr 9 22:19:27 2026 -0400

    x86-64: Rearrange CAS vops for SYMBOL-[GLOBAL-]VALUE
    
    Don't attempt to share logic between SYMBOL-VALUE and SYMBOL-GLOBAL-VALUE
    for sb-thread but instead make sb-thread (CAS SYMBOL-GLOBAL-VALUE)
    identical to #-sb-thread (CAS SYMBOL-VALUE) and then separately implement
    (CAS SYMBOL-VALUE) for threads. Also correct the deficiency of not
    accepting immediate SC for the symbol on #-sb-thread.
---
 src/compiler/x86-64/cell.lisp   | 48 ++++++++++++++++++---------------
 src/compiler/x86-64/memory.lisp |  4 +++
 src/compiler/x86-64/tls.lisp    | 59 +++++++++++------------------------------
 3 files changed, 46 insertions(+), 65 deletions(-)

diff --git a/src/compiler/x86-64/cell.lisp b/src/compiler/x86-64/cell.lisp
index 982b24f04..100b139c8 100644
--- a/src/compiler/x86-64/cell.lisp
+++ b/src/compiler/x86-64/cell.lisp
@@ -149,6 +149,33 @@
                         (object-slot-ea symbol symbol-value-slot other-pointer-lowtag))
         value val-temp))))
 
+(define-vop (%cas-symbol-global-value)
+  (:translate %cas-symbol-global-value #-sb-thread %compare-and-swap-symbol-value)
+  (:args (symbol :scs (descriptor-reg immediate) :to (:result 0))
+         (old :scs (descriptor-reg any-reg constant immediate))
+         (new :scs (descriptor-reg any-reg)))
+  ;; RAX purposely conflicts with OLD instead of being born exactly when OLD dies
+  ;; because RAX serves as the temporary for computing the card mark address.
+  (:temporary (:sc descriptor-reg :offset rax-offset :to (:result 0)) rax)
+  (:results (result :scs (descriptor-reg any-reg)))
+  (:policy :fast-safe)
+  (:vop-var vop)
+  (:node-var node)
+  (:generator 15
+    (pseudo-atomic (:elide-if (and #+immobile-space
+                                   (not (symbol-set-barrier-p symbol (vop-nth-arg 2 vop)))))
+      (emit-symbol-write-barrier vop symbol rax (vop-nth-arg 2 vop))
+      (if (sc-is old immediate) (move-immediate rax (immediate-tn-repr old)) (move rax old))
+      (let ((ea (if (sc-is symbol immediate)
+                    (symbol-slot-ea (tn-value symbol) symbol-value-slot)
+                    (symbol-value-slot-ea symbol))))
+        (inst cmpxchg :lock ea new)))
+    (unless (or (and (sc-is symbol immediate) (sb-c::always-boundp (tn-value symbol) node))
+                (policy node (= safety 0)))
+      (inst cmp :byte rax unbound-marker-widetag)
+      (inst jmp :e (generate-error-code vop 'unbound-symbol-error symbol)))
+    (move result rax)))
+
 #-sb-thread
 (progn
   (define-vop (symbol-value symbol-global-value)
@@ -166,27 +193,6 @@
                  symbol symbol-value-slot other-pointer-lowtag)
             unbound-marker-widetag)))
 
-  (define-vop (%compare-and-swap-symbol-value)
-    (:translate %compare-and-swap-symbol-value %cas-symbol-global-value)
-    (:args (symbol :scs (descriptor-reg) :to (:result 0))
-           (old :scs (descriptor-reg any-reg constant immediate))
-           (new :scs (descriptor-reg any-reg)))
-    (:temporary (:sc descriptor-reg :offset rax-offset :to (:result 0)) rax)
-    (:results (result :scs (descriptor-reg any-reg)))
-    (:policy :fast-safe)
-    (:vop-var vop)
-    (:node-var node)
-    (:generator 15
-      (emit-symbol-write-barrier vop symbol rax (vop-nth-arg 2 vop))
-      (if (sc-is old immediate)
-          (move-immediate rax (immediate-tn-repr old))
-          (move rax old))
-      (inst cmpxchg :lock (object-slot-ea symbol symbol-value-slot other-pointer-lowtag) new)
-      (unless (policy node (= safety 0))
-        (inst cmp :byte rax unbound-marker-widetag)
-        (inst jmp :e (generate-error-code vop 'unbound-symbol-error symbol)))
-      (move result rax)))
-
   (define-vop (dynbind)
     (:args (val :scs (any-reg descriptor-reg))
            (symbol :scs (descriptor-reg)))
diff --git a/src/compiler/x86-64/memory.lisp b/src/compiler/x86-64/memory.lisp
index 8ffc2be3b..08cefb65d 100644
--- a/src/compiler/x86-64/memory.lisp
+++ b/src/compiler/x86-64/memory.lisp
@@ -18,6 +18,10 @@
         (ea (+ (static-symbol-offset symbol) offset) null-tn)
         (ea (make-fixup symbol :immobile-symbol offset)))))
 
+(defmacro symbol-value-slot-ea (sym)    ; SYM is a TN
+  `(ea (- (* symbol-value-slot n-word-bytes) other-pointer-lowtag)
+       ,sym))
+
 ;;; The GC card table base is either an imm8 displacement from NULL-TN, or that
 ;;; plus one backend page if #+sb-safepoint. The reason for sliding the table up
 ;;; with #+sb-safepoint is that the safepoint trap address wants to be an imm8 away
diff --git a/src/compiler/x86-64/tls.lisp b/src/compiler/x86-64/tls.lisp
index 3d310e38b..836f151f2 100644
--- a/src/compiler/x86-64/tls.lisp
+++ b/src/compiler/x86-64/tls.lisp
@@ -11,10 +11,6 @@
 
 (in-package "SB-VM")
 
-(defmacro symbol-value-slot-ea (sym)    ; SYM is a TN
-  `(ea (- (* symbol-value-slot n-word-bytes) other-pointer-lowtag)
-       ,sym))
-
 (defun emit-lea-symbol-value-slot (ea-tn symbol) ; dest, src
   (if (sc-is symbol immediate)
       (inst mov ea-tn (make-fixup (tn-value symbol) :immobile-symbol
@@ -39,36 +35,6 @@
       `(%cas-symbol-global-value symbol old new)
       (sb-c::give-up-ir1-transform)))
 
-(flet ((emit-cas (ea symbol old new rax result pa vop &aux (node (sb-c::vop-node vop)))
-         (if (sc-is old immediate) (move-immediate rax (immediate-tn-repr old)) (move rax old))
-         (inst cmpxchg :lock ea new)
-         (when pa (emit-end-pseudo-atomic))
-         (unless (or (and (sc-is symbol immediate) (sb-c::always-boundp (tn-value symbol) node))
-                     (policy node (= safety 0)))
-           (inst cmp :byte rax unbound-marker-widetag)
-           (inst jmp :e (generate-error-code vop 'unbound-symbol-error symbol)))
-         (move result rax)))
-(define-vop (%cas-symbol-global-value)
-  (:translate %cas-symbol-global-value)
-  (:args (symbol :scs (descriptor-reg immediate) :to (:result 0))
-         (old :scs (descriptor-reg any-reg constant immediate))
-         (new :scs (descriptor-reg any-reg)))
-  ;; RAX is the temp for computing the card mark, so it has to conflict
-  ;; with OLD and therefore the default lifetime spec is fine
-  (:temporary (:sc descriptor-reg :offset rax-offset :to (:result 0)) rax)
-  (:results (result :scs (descriptor-reg any-reg)))
-  (:policy :fast-safe)
-  (:vop-var vop)
-  (:generator 10
-    ;; There's an error trap in EMIT-CAS which mustn't be inside PSEUDO-ATOMIC
-    (let ((pa #+immobile-space (symbol-set-barrier-p symbol (vop-nth-arg 2 vop))))
-      (when pa (emit-begin-pseudo-atomic))
-      (emit-symbol-write-barrier vop symbol rax (vop-nth-arg 2 vop))
-      (emit-cas (if (sc-is symbol immediate)
-                    (symbol-slot-ea (tn-value symbol) symbol-value-slot)
-                    (symbol-value-slot-ea symbol))
-                symbol old new rax result pa vop))))
-
 (define-vop (%compare-and-swap-symbol-value)
   (:translate %compare-and-swap-symbol-value)
   (:args (symbol :scs (descriptor-reg immediate) :to (:result 0))
@@ -81,6 +47,7 @@
   (:results (result :scs (descriptor-reg any-reg)))
   (:policy :fast-safe)
   (:vop-var vop)
+  (:node-var node)
   (:generator 15
   ;; This code has two pathological cases: NO-TLS-VALUE-MARKER
   ;; or UNBOUND-MARKER as NEW: in either case we would end up
@@ -95,16 +62,20 @@
     ;; IF this is CAS of a thread-local value, then pseudo-atomic is not needed,
     ;; but trying to skip the p-a (to "optimize") is just silly because we have
     ;; to assume that this is NOT thread-local for CAS to have any merit.
-    (let ((pa #+immobile-space (symbol-set-barrier-p symbol (vop-nth-arg 2 vop)))
-          (cas (gen-label)))
-      (when pa (emit-begin-pseudo-atomic))
-      (inst cmp :qword (ea cell) no-tls-value-marker)
-      (inst jmp :ne CAS)
-      ;; GLOBAL
-      (emit-symbol-write-barrier vop symbol cell (vop-nth-arg 2 vop))
-      (emit-lea-symbol-value-slot cell symbol)
-      (emit-label CAS)
-      (emit-cas (ea cell) symbol old new rax result pa vop)))))
+    (let ((pa #+immobile-space (symbol-set-barrier-p symbol (vop-nth-arg 2 vop))))
+      (pseudo-atomic (:elide-if (not pa))
+        (inst cmp :qword (ea cell) no-tls-value-marker)
+        (inst jmp :ne CAS)
+        (emit-symbol-write-barrier vop symbol cell (vop-nth-arg 2 vop))
+        (emit-lea-symbol-value-slot cell symbol)
+        CAS
+        (if (sc-is old immediate) (move-immediate rax (immediate-tn-repr old)) (move rax old))
+        (inst cmpxchg :lock (ea cell) new))
+      (unless (or (and (sc-is symbol immediate) (sb-c::always-boundp (tn-value symbol) node))
+                  (policy node (= safety 0)))
+        (inst cmp :byte rax unbound-marker-widetag)
+        (inst jmp :e (generate-error-code vop 'unbound-symbol-error symbol)))
+      (move result rax))))
 
 ;;; The :tls-load-indirect feature is, in most situations, an improvement over "direct"
 ;;; access (contrary to what indirection implies, but I couldn't settle on a better name).

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


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.