]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: use generics for sparse map
authorKeith Randall <khr@golang.org>
Thu, 12 Jun 2025 00:14:59 +0000 (17:14 -0700)
committerGopher Robot <gobot@golang.org>
Thu, 24 Jul 2025 16:04:22 +0000 (09:04 -0700)
So it is easier to reuse this code with different key/value types.

Change-Id: I5a9e669769cf359b32f2fe784594868acdee4d02
Reviewed-on: https://go-review.googlesource.com/c/go/+/681175
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: David Chase <drchase@google.com>
Auto-Submit: Keith Randall <khr@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
src/cmd/compile/internal/ssa/biasedsparsemap.go
src/cmd/compile/internal/ssa/deadstore.go
src/cmd/compile/internal/ssa/sparsemap.go

index 948aef9a9ba86060d6fb43f6155cbaabff9a23db..c08efbf1621394a5f6c15ee53d043a5c6f29d02e 100644 (file)
@@ -68,7 +68,11 @@ func (s *biasedSparseMap) get(x uint) int32 {
        if int(x) >= s.cap() {
                return -1
        }
-       return s.s.get(ID(int(x) - s.first))
+       k := ID(int(x) - s.first)
+       if !s.s.contains(k) {
+               return -1 // TODO: push presence check to callers?
+       }
+       return s.s.get(k)
 }
 
 // getEntry returns the i'th key and value stored in s,
index f8c69dc6984d787b3aea367bdb903e5a6ecb10fa..40905bedcf19cf959085d4ce77bacb4c54724f16 100644 (file)
@@ -156,9 +156,7 @@ func dse(f *Func) {
 
 // A shadowRange encodes a set of byte offsets [lo():hi()] from
 // a given pointer that will be written to later in the block.
-// A zero shadowRange encodes an empty shadowed range (and so
-// does a -1 shadowRange, which is what sparsemap.get returns
-// on a failed lookup).
+// A zero shadowRange encodes an empty shadowed range.
 type shadowRange int32
 
 func (sr shadowRange) lo() int64 {
index 9443c8b4b43aa648e26318d3631e317af5d00782..b7363b36ebeecb00a2d1e855e814b108afdf8384 100644 (file)
@@ -7,70 +7,60 @@ package ssa
 // from https://research.swtch.com/sparse
 // in turn, from Briggs and Torczon
 
-type sparseEntry struct {
-       key ID
-       val int32
+// sparseKey needs to be something we can index a slice with.
+type sparseKey interface{ ~int | ~int32 }
+
+type sparseEntry[K sparseKey, V any] struct {
+       key K
+       val V
 }
 
-type sparseMap struct {
-       dense  []sparseEntry
+type genericSparseMap[K sparseKey, V any] struct {
+       dense  []sparseEntry[K, V]
        sparse []int32
 }
 
-// newSparseMap returns a sparseMap that can map
-// integers between 0 and n-1 to int32s.
-func newSparseMap(n int) *sparseMap {
-       return &sparseMap{dense: nil, sparse: make([]int32, n)}
+// newGenericSparseMap returns a sparseMap that can map
+// integers between 0 and n-1 to a value type.
+func newGenericSparseMap[K sparseKey, V any](n int) *genericSparseMap[K, V] {
+       return &genericSparseMap[K, V]{dense: nil, sparse: make([]int32, n)}
 }
 
-func (s *sparseMap) cap() int {
+func (s *genericSparseMap[K, V]) cap() int {
        return len(s.sparse)
 }
 
-func (s *sparseMap) size() int {
+func (s *genericSparseMap[K, V]) size() int {
        return len(s.dense)
 }
 
-func (s *sparseMap) contains(k ID) bool {
+func (s *genericSparseMap[K, V]) contains(k K) bool {
        i := s.sparse[k]
        return i < int32(len(s.dense)) && s.dense[i].key == k
 }
 
-// get returns the value for key k, or -1 if k does
-// not appear in the map.
-func (s *sparseMap) get(k ID) int32 {
+// get returns the value for key k, or the zero V
+// if k does not appear in the map.
+func (s *genericSparseMap[K, V]) get(k K) V {
        i := s.sparse[k]
        if i < int32(len(s.dense)) && s.dense[i].key == k {
                return s.dense[i].val
        }
-       return -1
+       var v V
+       return v
 }
 
-func (s *sparseMap) set(k ID, v int32) {
+func (s *genericSparseMap[K, V]) set(k K, v V) {
        i := s.sparse[k]
        if i < int32(len(s.dense)) && s.dense[i].key == k {
                s.dense[i].val = v
                return
        }
-       s.dense = append(s.dense, sparseEntry{k, v})
-       s.sparse[k] = int32(len(s.dense)) - 1
-}
-
-// setBit sets the v'th bit of k's value, where 0 <= v < 32
-func (s *sparseMap) setBit(k ID, v uint) {
-       if v >= 32 {
-               panic("bit index too large.")
-       }
-       i := s.sparse[k]
-       if i < int32(len(s.dense)) && s.dense[i].key == k {
-               s.dense[i].val |= 1 << v
-               return
-       }
-       s.dense = append(s.dense, sparseEntry{k, 1 << v})
+       s.dense = append(s.dense, sparseEntry[K, V]{k, v})
        s.sparse[k] = int32(len(s.dense)) - 1
 }
 
-func (s *sparseMap) remove(k ID) {
+func (s *genericSparseMap[K, V]) remove(k K) {
        i := s.sparse[k]
        if i < int32(len(s.dense)) && s.dense[i].key == k {
                y := s.dense[len(s.dense)-1]
@@ -80,10 +70,18 @@ func (s *sparseMap) remove(k ID) {
        }
 }
 
-func (s *sparseMap) clear() {
+func (s *genericSparseMap[K, V]) clear() {
        s.dense = s.dense[:0]
 }
 
-func (s *sparseMap) contents() []sparseEntry {
+func (s *genericSparseMap[K, V]) contents() []sparseEntry[K, V] {
        return s.dense
 }
+
+type sparseMap = genericSparseMap[ID, int32]
+
+// newSparseMap returns a sparseMap that can map
+// integers between 0 and n-1 to int32s.
+func newSparseMap(n int) *sparseMap {
+       return newGenericSparseMap[ID, int32](n)
+}