Skip to content
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: unnecessary runtime.growslice with provable capacity #66692

Open
dsnet opened this issue Apr 5, 2024 · 3 comments
Open

cmd/compile: unnecessary runtime.growslice with provable capacity #66692

dsnet opened this issue Apr 5, 2024 · 3 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Performance
Milestone

Comments

@dsnet
Copy link
Member

dsnet commented Apr 5, 2024

Go version

go1.22

Output of go env in your module/workspace:

GOARCH=amd64
GOOS=linux

What did you do?

Compile the following:

package main

import "encoding/binary"

var src uint64
var dst []byte

func main() {
	if cap(dst)-len(dst) < 8 {
		return
	}
	dst = binary.BigEndian.AppendUint64(dst, src)
}

What did you see happen?

I see the following in the assembly:

	0x004a 00074 (/usr/local/go1.22.0/src/encoding/binary/binary.go:201)	MOVL	$8, DI
	0x004f 00079 (/usr/local/go1.22.0/src/encoding/binary/binary.go:201)	LEAQ	type:uint8(SB), SI
	0x0056 00086 (/usr/local/go1.22.0/src/encoding/binary/binary.go:201)	PCDATA	$1, $0
	0x0056 00086 (/usr/local/go1.22.0/src/encoding/binary/binary.go:201)	CALL	runtime.growslice(SB)
	0x005b 00091 (/usr/local/go1.22.0/src/encoding/binary/binary.go:201)	MOVQ	encoding/binary.v+64(SP), DX
	0x0060 00096 (/usr/local/go1.22.0/src/encoding/binary/binary.go:201)	BSWAPQ	DX
	0x0063 00099 (/usr/local/go1.22.0/src/encoding/binary/binary.go:201)	MOVQ	DX, -8(BX)(AX*1)

What did you expect to see?

No call to runtime.growslice.

This particular example seems silly, but the capacity check already happens elsewhere in code beforehand so there is no possible way that growslice would be necessary once we get to AppendUint64.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Apr 5, 2024
@dsnet dsnet added Performance compiler/runtime Issues related to the Go compiler and/or runtime. and removed compiler/runtime Issues related to the Go compiler and/or runtime. labels Apr 5, 2024
@dsnet
Copy link
Member Author

dsnet commented Apr 5, 2024

A fix for this should hopefully take #66691 into account such that the following avoids both growslice calls for subsequent append calls:

if cap(dst)-len(dst) < 1+8 {
	dst = slices.Grow(dst, 1+8)
}
dst = append(dst, flag)
dst = binary.BigEndian.AppendUint64(dst, src)

(Obviously, slices.Grow would need to call growslice, but after the conditional check we should be safe for subsequent append operations)

@Jorropo
Copy link
Member

Jorropo commented Apr 5, 2024

With lots of massaging this works:

package main

import "encoding/binary"

var src uint64
var dst []byte

func main() {
	if uint(len(dst)+8) > uint(cap(dst)) {
		return
	}
	dst = binary.BigEndian.AppendUint64(dst, src)
}

This works because uint(len(dst)+8) > uint(cap(dst)) is the exact check generated by the frontend for this append.

I see at least two things here:

  • SliceLen and SliceCap doesn't seems to be recognized as uint63 or uint31 as else Less64 and Less64U should already prove each other https://godbolt.org/z/h9dYfY19M.
  • More general equivalence or canonicalization issues.

@dmitshur dmitshur added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Apr 5, 2024
@dmitshur dmitshur added this to the Backlog milestone Apr 5, 2024
@dmitshur
Copy link
Contributor

dmitshur commented Apr 5, 2024

CC @golang/compiler.

@mknyszek mknyszek modified the milestones: Backlog, Unplanned Apr 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Performance
Projects
Status: No status
Development

No branches or pull requests

5 participants