-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cmd/compile: teach prove about slice expressions #28941
Labels
Milestone
Comments
Found an especially bad case of it while debugging gio (https://go.godbolt.org/z/hc44d5):
Note, the problem disappears when using |
This was referenced Nov 23, 2020
Specifying lengths also makes the problem disappear.
And the following code doesn't need bound checking:
|
More observations indicate this is caused by code inline: package ex
import (
"math"
"encoding/binary"
)
type Point struct { X, Y float32 }
type Quad struct { From, Ctrl, To Point }
func EncodeQuad(d []byte, q Quad) {
if len(d) < 24 {
return
}
binary.LittleEndian.PutUint32(d[0:], math.Float32bits(q.From.X))
PutUint32_NoInline(d[4:], math.Float32bits(q.From.Y))
PutUint32_MayInline(d[8:], math.Float32bits(q.Ctrl.X)) // bounds check
t.PutUint32_NoInline(d[12:], math.Float32bits(q.Ctrl.Y))
t.PutUint32_MayInline(d[16:], math.Float32bits(q.To.X)) // bounds check
//PutUint32(d[20:], math.Float32bits(q.To.Y))
{
b, v := d[20:], math.Float32bits(q.To.Y)
_ = b[3] // bounds check
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
b[2] = byte(v >> 8)
b[3] = byte(v)
}
}
//go:noinline
func PutUint32_NoInline(b []byte, v uint32) {
_ = b[3] // bounds check
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
b[2] = byte(v >> 8)
b[3] = byte(v)
}
func PutUint32_MayInline(b []byte, v uint32) {
_ = b[3] // bounds check
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
b[2] = byte(v >> 8)
b[3] = byte(v)
}
type T struct{}
var t T
//go:noinline
func (T) PutUint32_NoInline(b []byte, v uint32) {
_ = b[3] // bounds check
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
b[2] = byte(v >> 8)
b[3] = byte(v)
}
func (T) PutUint32_MayInline(b []byte, v uint32) {
_ = b[3] // bounds check
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
b[2] = byte(v >> 8)
b[3] = byte(v)
} |
It is strange that only the first line eliminates bounds check:
|
gopherbot
added
the
compiler/runtime
Issues related to the Go compiler and/or runtime.
label
Jul 13, 2022
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
The bounds check disappears as soon as we rewrite the code to not reslice
s
. This shows up in real code fairly often, for example, I encountered it in a somewhat hot function in theencoding/json
decoder:I'm not sure how easy it would be to make the prove pass aware of slice expressions. I think handling the simple
x = x[N:]
case (whereN
is constant) should be doable, and hopefully remove a few dozen bounds checks across the standard library./cc @aclements @rasky @josharian
The text was updated successfully, but these errors were encountered: