Go版本
go版本 go1.22.2 darwin/arm64
在你的模块/工作区中go env
的输出:
GO111MODULE=''
GOARCH='arm64'
GOBIN=''
GOCACHE='/Users/filippo/Library/Caches/go-build'
GOENV='/Users/filippo/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/filippo/pkg/mod'
GONOPROXY='github.com/FiloSottile/*,filippo.io/*'
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/filippo'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org'
GOROOT='/Users/filippo/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.2.darwin-arm64'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/Users/filippo/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.2.darwin-arm64/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.22.2'
GCCGO='gccgo'
AR='ar'
CC='clang'
CXX='clang++'
CGO_ENABLED='1'
GOMOD='/Users/filippo/src/filippo.io/mlkem768/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/_j/hq4ytn1n4b94fhrpvvb9tktr0000gn/T/go-build3556564162=/tmp/go-build -gno-record-gcc-switches -fno-common'
你做了什么?
我在一个相当热的循环中有一个这样的函数。
const n = 256
type fieldElement uint16
type nttElement [n]fieldElement
func nttMul(f, g nttElement) nttElement {
var h nttElement
for i := 0; i < 128; i++ {
a0, a1 := f[2*i], f[2*i+1]
b0, b1 := g[2*i], g[2*i+1]
h[2*i] = fieldAdd(fieldMul(a0, b0), fieldMul(fieldMul(a1, b1), gammas[i]))
h[2*i+1] = fieldAdd(fieldMul(a0, b1), fieldMul(a1, b0))
}
return h
}
你看到了什么发生?
f[2*i]
和f[2*i+1]
都得到了一个isInBounds()
。而g[2*i]
和g[2*i+1]
没有。
你期望看到什么?
一次或零次边界检查。
如果编译器意识到如果f[2*i+1]
在i
的范围内且为正数且较小(0到127),那么f[2*i]
显然在范围内。
如果编译器算出i的范围是0到127,那么2*i+1
的范围是0到255,而f的大小是一个常数256。
8条答案
按热度按时间vs3odd8k1#
看起来现在有一个解决方法:
还没有对其进行基准测试。
[edit]顺便说一下,为什么不使用切片作为参数呢?
m4pnthwp2#
这确实移除了对
f
的边界检查,但我们得到了一个对gammas[i/2]
的边界检查,这也感觉是可以避免的。理论上,切片应该比const大小的数组增加开销,并从类型系统中删除信息。
92dk7w1h3#
是的,仍然有一些 BCE 无法处理。
现在,一个解决方法是将
gammas
的长度加倍,并仅使用其在2N
索引处的元素。xa9qqrwz4#
现在,一个解决方法是将
gammas
的长度加倍,并仅使用其在2N
索引处的元素。有趣的是,这些基准测试明显更差,消耗了删除f
边界检查速度提升的 10% 到 20%。🤷c7rzv4ha5#
这是可能的。BCE并不总是产生积极的效果。
另一种移除所有绑定检查的方法是声明
fieldElement
为[2]uint16
。我不确定最终效果如何。vuktfyat6#
简单的复制器:
我们应该能够去除边界检查。目前我认为它失败了,因为证明传递无法告诉数学
2*i
不会溢出并变为负数。它似乎确实理解了2*i < 256
。应该是可以修复的。然而,这段代码很微妙,对我来说,立即明显地知道修复在哪里并不容易。
aelbi1ox7#
https://go.dev/cl/599096提到了这个问题:
cmd/compile: rewrite the constant parts of the prove pass
5w9g7ksd8#
https://go.dev/cl/599256提到了这个问题:
cmd/compile: propagate constant ranges through multiplies and shifts