-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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: implement type-based alias analysis #70488
Comments
The reason CSE or other SSA optimizations didn’t eliminated the read of However, this can be done based on type aliasing rules. My reading of the rules (https://pkg.go.dev/unsafe#Pointer) is that no non-pointer type (like |
I implemented a patch that adds type-based alias analysis. Here it goes:
It kicks in and enables additional optimizations in a few spots in the standard library and a real-world program I tried (etcd). For example, it enables removal of However, this doesn't bring any tangible benefits to
@mundaym , @randall77 , it seems you are the primary authors of Andrey |
You'll want to read through https://go-review.googlesource.com/c/go/+/551381 first. I think possibly your ptr vs nonptr rule might work, but not the rest. |
@randall77 thanks for pointing at this CL; I wasn't aware of it! I read through your comments; I believe they are already handled in my code. Essentially, what my patch does is what you proposed in your comment to CL551381:
The only "extra" is I tested this patch on Andrey |
That doesn't sound right. For example, here is a program that stores both channel and map values in the same memory location. This is a dreadful program but it's valid Go. package main
import (
"fmt"
"unsafe"
)
type union struct {
f chan int // sometimes this is a map
}
func (u *union) setChan(c chan int) {
u.f = c
}
func (u *union) getChan() chan int {
return u.f
}
func (u *union) setMap(m map[int]bool) {
u.f = *(*chan int)(unsafe.Pointer(&m))
}
func (u *union) getMap() map[int]bool {
return *(*map[int]bool)(unsafe.Pointer(&u.f))
}
func main() {
u := union{f: make(chan int)}
u.setChan(make(chan int, 1))
close(u.getChan())
u.setMap(map[int]bool{1: true})
fmt.Println(u.getMap()[1])
} |
Hi @ianlancetaylor , unsafe.Pointer's doc says the following on allowable conversions:
(highlighting is mine) I don't think a Go user can make any assumptions on
...said this, I understand that Go generally prefers simplicity vs squeezing the last bit of performance; so perhaps as a first step, we can just add a rule saying that no Type can alias with a pointer? It seems there is a universal agreement this is guaranteed by the language and easy to learn and reason about. This rule triggers a lot of times during Go compiler build -- and leads to some actual optimizations (see an example from Andrey |
map and chan values are pointers, and as such have equivalent memory layout. The structs you mention are what those pointers point to. My sample program above is just changing pointers. I agree that in the current implementation a pointer and a non-pointer can not share the same memory, and that it follows that changing memory using a |
Change https://go.dev/cl/632176 mentions this issue: |
Ouch! -- I thought they are represented as full data structures in SSA. Live and learn! OK, it seems everyone agree that a pointer and a non-pointer can't alias; CL#632176 submitted. @randall77 , @ianlancetaylor , please kindly take a look when you'll have a spare moment. Andrey |
Go version
go version devel go1.24-3ca78afb3b Mon Nov 18 04:56:52 2024 +0000 linux/arm64
Output of
go env
in your module/workspace:What did you do?
Test case:
Compiled with
go build -a -gcflags='-d ssa/all/dump=Foo' test.go
.What did you see happen?
Read of
*y
memory location and thus, the subsequent addition of a constant are not eliminated:What did you expect to see?
Read of
*y
eliminated; subsequent addition of two constant values (10
, which is the value of*y
and20
) folded.The text was updated successfully, but these errors were encountered: