Go version
go version go1.21.6 linux/amd64
Output of go env in your module/workspace:
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/root/.cache/go-build'
GOENV='/root/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/root/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/root/go'
GOPRIVATE=''
GOPROXY='https://goproxy.cn'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.6'
GCCGO='/usr/local/bin/gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/dev/null'
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 -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build734905149=/tmp/go-build -gno-record-gcc-switches'
What did you do?
Use GOSSAFUNC=enc go build qmac.go or go tool compile -S qmac.go for its assembly results or see https://godbolt.org/z/9GxzbY4eP.
//qmac.go
package main
func main() {}
type desc struct {
t int
x int
y int
z int
p int
}
func enc(d []byte) []byte {
var buf = d
t, a, b, c, pr := 0, -1, 3, 1, 113
for i := 0; i < len(buf); i++ {
res := process(t, a, b, c, pr)
buf[i] = byte(res.z)
}
return buf
}
//go:noinline
func process(t, a, b, c, pr int) desc {
d := desc{
t: t,
x : a,
y: b,
z: c,
p: pr,
}
//...
return d
}
What did you see happen?
For every loop Go compiler stores the call result into onstack variable main.res, which is meaningless, as main.res is only an intermediate result for setting buf[i].
I also haven't figured out what autotmp_11 is used for here, why not doing a direct store MOVQ AX, main.res-xx(SP) instead of MOVQ AX, main..autotmp_11-40(SP), MOVQ main..autotmp_11-40(SP), DX, MOVQ DX, main.res-80(SP)
What did you expect to see?
Compiler can optimize the redundant store operations like following case.
(reduce process's parameters from 5 to 4)
//qmac2.go
package main
func main() {}
type desc struct {
t int
x int
y int
z int
}
func enc(d []byte) []byte {
var buf = d
t, a, b, c := 0, -1, 3, 1
for i := 0; i < len(buf); i++ {
res := process(t, a, b, c)
buf[i] = byte(res.z)
}
return buf
}
//go:noinline
func process(t, a, b, c int) desc {
d := desc{
t: t,
x : a,
y: b,
z: c,
}
//...
return d
}
Go version
go version go1.21.6 linux/amd64
Output of
go envin your module/workspace:What did you do?
Use
GOSSAFUNC=enc go build qmac.goorgo tool compile -S qmac.gofor its assembly results or see https://godbolt.org/z/9GxzbY4eP.What did you see happen?
For every loop Go compiler stores the call result into onstack variable
main.res, which is meaningless, asmain.resis only an intermediate result for settingbuf[i].I also haven't figured out what
autotmp_11is used for here, why not doing a direct storeMOVQ AX, main.res-xx(SP)instead ofMOVQ AX, main..autotmp_11-40(SP),MOVQ main..autotmp_11-40(SP), DX,MOVQ DX, main.res-80(SP)What did you expect to see?
Compiler can optimize the redundant store operations like following case.
(reduce
process's parameters from 5 to 4)