mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: add type-based alias analysis
Make ssa.disjoint call ssa.disjointTypes to disambiguate Values based on their types. Only one type-based rule is employed: a Type can't alias with a pointer (https://pkg.go.dev/unsafe#Pointer). Fixes #70488 Change-Id: I5a7e75292c2b6b5a01fb9048e3e2360e31dbcdd9 Reviewed-on: https://go-review.googlesource.com/c/go/+/632176 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@golang.org> Auto-Submit: Keith Randall <khr@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
parent
2299a4289d
commit
11f7ea8ce0
3 changed files with 144 additions and 22 deletions
|
|
@ -4,7 +4,12 @@
|
|||
|
||||
package ssa
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"cmd/compile/internal/rttype"
|
||||
"reflect"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// We generate memmove for copy(x[1:], x[:]), however we may change it to OpMove,
|
||||
// because size is known. Check that OpMove is alias-safe, or we did call memmove.
|
||||
|
|
@ -218,3 +223,65 @@ func TestMergePPC64AndSrwi(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisjointTypes(t *testing.T) {
|
||||
tests := []struct {
|
||||
v1, v2 any // two pointers to some types
|
||||
expected bool
|
||||
}{
|
||||
{new(int8), new(int8), false},
|
||||
{new(int8), new(float32), false},
|
||||
{new(int8), new(*int8), true},
|
||||
{new(*int8), new(*float32), false},
|
||||
{new(*int8), new(chan<- int8), false},
|
||||
{new(**int8), new(*int8), false},
|
||||
{new(***int8), new(**int8), false},
|
||||
{new(int8), new(chan<- int8), true},
|
||||
{new(int), unsafe.Pointer(nil), false},
|
||||
{new(byte), new(string), false},
|
||||
{new(int), new(string), false},
|
||||
{new(*int8), new(struct{ a, b int }), true},
|
||||
{new(*int8), new(struct {
|
||||
a *int
|
||||
b int
|
||||
}), false},
|
||||
{new(*int8), new(struct {
|
||||
a int
|
||||
b *int
|
||||
}), false}, // with more precise analysis it should be true
|
||||
{new(*byte), new(string), false},
|
||||
{new(int), new(struct {
|
||||
a int
|
||||
b *int
|
||||
}), false},
|
||||
{new(float64), new(complex128), false},
|
||||
{new(*byte), new([]byte), false},
|
||||
{new(int), new([]byte), false},
|
||||
{new(int), new([2]*byte), false}, // with more recise analysis it should be true
|
||||
{new([2]int), new(*byte), true},
|
||||
}
|
||||
for _, tst := range tests {
|
||||
t1 := rttype.FromReflect(reflect.TypeOf(tst.v1))
|
||||
t2 := rttype.FromReflect(reflect.TypeOf(tst.v2))
|
||||
result := disjointTypes(t1, t2)
|
||||
if result != tst.expected {
|
||||
t.Errorf("disjointTypes(%s, %s) got %t expected %t", t1.String(), t2.String(), result, tst.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func foo(p1 *int64, p2 *float64) int64 {
|
||||
*p1 = 10
|
||||
*p2 = 0 // disjointTypes shouldn't consider this and preceding stores as non-aliasing
|
||||
return *p1
|
||||
}
|
||||
|
||||
func TestDisjointTypesRun(t *testing.T) {
|
||||
f := float64(0)
|
||||
i := (*int64)(unsafe.Pointer(&f))
|
||||
r := foo(i, &f)
|
||||
if r != 0 {
|
||||
t.Errorf("disjointTypes gives an incorrect answer that leads to an incorrect optimization.")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue