diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v
index 41ebd16fb54a01a73a16f2b0dc3c6118916dfbc3..30eb83c697b0b4b27ef576356895d4b2c908c073 100644
--- a/theories/heap_lang/lang.v
+++ b/theories/heap_lang/lang.v
@@ -367,18 +367,46 @@ Definition bin_op_eval (op : bin_op) (v1 v2 : val) : option val :=
   | _, _ => None
   end.
 
-(** Return whether it is possible to use CAS to compare vl (current value) with v1 (netest value). *)
+(** Return whether it is possible to use CAS to compare vl (current value) with
+v1 (netest value).
+
+We assume the following encoding of values to 64-bit words: The least 3
+significant bits of every word are a "tag", and we have 61 bits of payload,
+which is enough if all pointers are 8-byte-aligned (commong on 64bit
+architectures). The tags have the following meaning:
+
+0: Payload is one of the following finitely many values, which 61 bits are more
+   than enough to encode: LitV LitUnit, LitV (LitBool _), NONEV, SOMEV (LitV
+   LitUnit), SOMEV (LitV (LitBool _)).
+1: Payload is the data for a LitV (LitInt _).
+2: Payload is the data for a SOMEV (LitV (LitInt _)).
+3: Payload is the data for a LitV (LitLoc _).
+4: Payload is the data for a SOMEV (LitV (LitLoc _)).
+5: Value is boxed, i.e., payload is a pointer to some read-only memory area on
+   the heap which stores whether this is a RecV, PairV, InjLV or InjRV and the
+   relevant data for those cases. However, the boxed representation is never
+   used if any of the above representations could be used.
+6: Unused.
+7: Unused.
+
+Ignoring (as usual) the fact that we have to fit the infinite Z/loc into 61
+bits, this means every value is machine-word-sized and can hence be atomically
+read and written. It also justifies the comparisons allowed for CAS: Whenever
+[vals_cas_compare_safe vl v1] holds, equality of the one-word representation of
+[vl] and [v1] is equivalent to equality of the abstract value represented. This
+is clear for [LitV _ == LitV _] and [SOMEV (LitV _) == SOMEV (LitV _)] because
+none of these are boxed. For [NONEV == v], we can't actually atomically load and
+compare the data for boxed values, but that's okay because we only have to know
+if they are equal to [NONEV] which is distinct from all boxed values.
+ *)
 Definition vals_cas_compare_safe (vl v1 : val) : Prop :=
   match vl, v1 with
-  (* We allow comparing literals with each other. *)
+  (* We allow comparing literals with each other, also when wrapped in a SOMEV. *)
   | LitV _, LitV _ => True
-  (* We assume that [NONEV] is represented as a NULL-pointer and [SOMEV x] as a
-  pointer to a location (never written to after allocation) storing [x].  Then
-  comparing [NONEV] with [NONEV] or [SOMEV x] is possible atomically by testing
-  for NULL.  Comparing [SOMEV x] with [SOMEV y] is not possible though. *)
-  | NONEV, NONEV => True
-  | NONEV, SOMEV _ => True
-  | SOMEV _, NONEV => True
+  | SOMEV (LitV _), SOMEV (LitV _) => True
+  (* We allow comparing NONEV to anything. *)
+  | NONEV, _ => True
+  | _, NONEV => True
   (* We don't allow comparing anything else. *)
   | _, _ => False
   end.