Description
I am currently working on some changes to the inliner for #15561, the current state of my work is https://go-review.googlesource.com/c/go/+/72490
While testing my changes, I noticed a very odd behavior, namely that code miscompiled when my inliner changes where triggered, was compiled correctly when passing the -m
flag.
The following code is reduced reproducer from a failure observed in generateTrace
from cmd/trace/trace.go
import (
"fmt"
)
type elem struct {
f uint64
}
func f() int {
m := make(map[uint64]*elem)
getOrCreate := func(g uint64) *elem {
info, ok := m[g]
if !ok {
info = &elem{}
m[g] = info
}
return info
}
getOrCreate(42)
return len(m)
}
func main() {
fmt.Println(f())
}
Diffing a disassembly of this program, compiled with - l -l
and -l -l -m
respectively, gives the following:
16c16
< 0x1091a6e 4889442420 MOVQ AX, 0x20(SP)
---
> 0x1091a6e 4889442430 MOVQ AX, 0x30(SP)
27c27
< 0x1091a9a 488b442420 MOVQ 0x20(SP), AX
---
> 0x1091a9a 488b442430 MOVQ 0x30(SP), AX
47c47
< 0x1091adf 488b4c2420 MOVQ 0x20(SP), CX
---
> 0x1091adf 488b4c2430 MOVQ 0x30(SP), CX
The only other reference to the 0x20(SP)
slot is, in both cases, the return value of the mapaccess call inside the inlined closure body :
0x1091a8c e86f7ff7ff CALL runtime.mapaccess2_fast64(SB)
0x1091a91 0fb6442420 MOVZX 0x20(SP), AX
I realize that there is probably something wrong with my inliner changes. However, I'm submitting this bug nonetheless because I find it very surprising that the -m
flag somehow fixes this issue, even though it should only affect compiler logs and not the resulting binary. This seems like it might be a latent issue in the compiler that would be worth fixing.
I have manually audited all locations that read Debug['m']
inside the compiler and didn't notice anything suspicious/side-effecty so I'm pretty stumped at this point and could use another pair of eyes.