]> Cypherpunks repositories - gostls13.git/commitdiff
internal/runtime/maps: shift optimizations
authorMichael Pratt <mpratt@google.com>
Wed, 21 Aug 2024 20:17:16 +0000 (16:17 -0400)
committerGopher Robot <gobot@golang.org>
Mon, 28 Oct 2024 21:25:50 +0000 (21:25 +0000)
Masking the shift lets the compiler elide a few instructions for
handling a shift of > 63 bits.

For #54766.

Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest-swissmap
Change-Id: I669fe01caa1de1b8521f1f56b6906f3e9066a39b
Reviewed-on: https://go-review.googlesource.com/c/go/+/611190
Auto-Submit: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
src/cmd/compile/internal/reflectdata/map_swiss.go
src/internal/runtime/maps/map.go

index a76864bdffb5f639efab63f9c494978f18086f2d..38a23908a6f2ec22945c75b877c133c7c54ef78c 100644 (file)
@@ -148,6 +148,7 @@ func SwissMapType() *types.Type {
        //     dirLen int
        //
        //     globalDepth uint8
+       //     globalShift uint8
        //     // N.B Padding
        //
        //     clearSeq uint64
@@ -160,6 +161,7 @@ func SwissMapType() *types.Type {
                makefield("dirPtr", types.Types[types.TUNSAFEPTR]),
                makefield("dirLen", types.Types[types.TINT]),
                makefield("globalDepth", types.Types[types.TUINT8]),
+               makefield("globalShift", types.Types[types.TUINT8]),
                makefield("clearSeq", types.Types[types.TUINT64]),
        }
 
index a4fa07635ae254a73243f585bb94cb4e9521c981..67e4bd6811ddf980d09e8086e6bf39f97a62d612 100644 (file)
@@ -233,11 +233,22 @@ type Map struct {
        // The number of bits to use in table directory lookups.
        globalDepth uint8
 
+       // The number of bits to shift out of the hash for directory lookups.
+       // On 64-bit systems, this is 64 - globalDepth.
+       globalShift uint8
+
        // clearSeq is a sequence counter of calls to Clear. It is used to
        // detect map clears during iteration.
        clearSeq uint64
 }
 
+func depthToShift(depth uint8) uint8 {
+       if goarch.PtrSize == 4 {
+               return 32 - depth
+       }
+       return 64 - depth
+}
+
 func NewMap(mt *abi.SwissMapType, capacity uint64) *Map {
        if capacity < abi.SwissMapGroupSlots {
                // TODO: temporary to simplify initial implementation.
@@ -259,6 +270,7 @@ func NewMap(mt *abi.SwissMapType, capacity uint64) *Map {
                //directory: make([]*table, dirSize),
 
                globalDepth: globalDepth,
+               globalShift: depthToShift(globalDepth),
        }
 
        if capacity > abi.SwissMapGroupSlots {
@@ -294,12 +306,7 @@ func (m *Map) directoryIndex(hash uintptr) uintptr {
        if m.dirLen == 1 {
                return 0
        }
-       // TODO(prattmic): Store the shift as globalShift, as we need that more
-       // often than globalDepth.
-       if goarch.PtrSize == 4 {
-               return hash >> (32 - m.globalDepth)
-       }
-       return hash >> (64 - m.globalDepth)
+       return hash >> (m.globalShift & 63)
 }
 
 func (m *Map) directoryAt(i uintptr) *table {
@@ -338,6 +345,7 @@ func (m *Map) installTableSplit(old, left, right *table) {
                        }
                }
                m.globalDepth++
+               m.globalShift--
                //m.directory = newDir
                m.dirPtr = unsafe.Pointer(&newDir[0])
                m.dirLen = len(newDir)