go ``` cmd/compile: 使用mapaccess1_fast64处理小键值 ```

1zmg4dgp  于 6个月前  发布在  Go
关注(0)|答案(6)|浏览(44)

Go版本
go1.22

在你的模块/工作区中,go env 的输出是什么?

GOARCH=amd64
GOOS=linux

你做了什么?

编译以下程序:

package main

type key struct {
	u16 uint16
	u8  bool
	u32 uint32
}

var map1 map[key]struct{}
var map2 map[uint64]struct{}
var key1 = key{}
var key2 = uint64(0)
var sink struct{}

func main() {
	sink = map1[key1]
	sink = map2[key2]
}

你看到了什么发生?

编译器输出:

0x0023 00035 (main.go:17)	CALL	runtime.mapaccess1(SB)
...
0x0040 00064 (main.go:18)	CALL	runtime.mapaccess1_fast64(SB)

你期望看到什么?

由于 key 类型小于一个uint64,所以希望在两者上都使用 runtime.mapaccess1_fast64
然而,这其中存在一些复杂性。例如,通过 unsafe ,有人可能会写入值到 bool 字段和 uint32 之间的填充空间。此外,使用 unsafe 的人可能会写入一个不是0或1的位模式到布尔值中。
我不确定这是可以依赖的事情。
然而,即使我们使 key 结构恰好为64位宽,没有填充且没有布尔值,它仍然不使用 runtime.mapaccess1_fast64

ycl3bljg

ycl3bljg1#

cc @randall77,这可能与#66413有关?

k5ifujac

k5ifujac2#

不直接相关,没有。
我们非常小心地不在填充中包含数据作为平等(因此哈希)的一部分。我不知道是否有人真正利用了这一点,但我不确定我们是否希望在这一点上改变它。这个假设可能已经在几个地方被烘焙出来了(例如,初始化栈变量的代码可能不会将这些字段当前设置为零)。
然而,即使我们使键结构恰好为64位宽,没有填充和布尔值,它仍然不使用runtime.mapaccess1_fast64。对我来说是这样。即使有布尔值。只有填充会导致问题。如果你有一个可以复现的问题,请仔细检查并发布一个复现示例?

4ktjp1zp

4ktjp1zp3#

你能检查一下并发布一个复现吗?
啊,你是对的。我当时用的是:

type key struct {
    a uint8
    b uint16
    c uint32
    d uint8
}

虽然加起来是64位,但我忘记了对齐。

flmtquvp

flmtquvp4#

由于mapaccess1_fast64通过寄存器传递键,并且我们知道在应用形状时类型中填充孔的位置,因此我们总是可以在调用运行时之前加载值并使用掩码将任何填充字节置零。

hujrc8aj

hujrc8aj5#

当然,这是个好主意。

dgiusagp

dgiusagp6#

一个复杂情况:mapacess1_fast64使用uint64 ==来比较键。因此,不仅mapacess1_fast64需要进行掩码操作,插入操作也需要进行掩码操作。

相关问题