[dev.simd] cmd/compile: exclude simd vars from merge local

It looks like mergelocals pass's liveness analysis does not handle simd
variables well.

The added test forces two vectors to spill in a way that does not work
with mergelocals: if the added check is removed, then `v` and `m` will
be marked merged and spilled to the same location, failing the test.

Change-Id: Ife4e4e939565d817fc24f7180cb791a5084dd191
Reviewed-on: https://go-review.googlesource.com/c/go/+/687375
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Junyang Shao 2025-07-10 22:04:21 +00:00
parent ccb43dcec7
commit 1440ff7036
2 changed files with 34 additions and 0 deletions

View file

@ -850,6 +850,13 @@ func (f *Func) NewLocal(pos src.XPos, typ *types.Type) *ir.Name {
// items larger than what CanSSA would allow (approximateky, we disallow things
// marked as open defer slots so as to avoid complicating liveness
// analysis.
//
// TODO: make SIMD variables mergible.
//
// Right now this check excludes SIMD vars because sometimes two live SIMD
// vectors will be put into the same partition by mergelocals, we need to figure
// out why because these vectors are big and should be merged when possible.
// Details in CL 687375.
func IsMergeCandidate(n *ir.Name) bool {
if base.Debug.MergeLocals == 0 ||
base.Flag.N != 0 ||
@ -857,6 +864,7 @@ func IsMergeCandidate(n *ir.Name) bool {
n.Type().Size() <= int64(3*types.PtrSize) ||
n.Addrtaken() ||
n.NonMergeable() ||
n.Type().IsSIMD() ||
n.OpenDeferSlot() {
return false
}

View file

@ -364,3 +364,29 @@ func TestSlicesFloat64(t *testing.T) {
}
}
}
// TODO: try to reduce this test to be smaller.
func TestMergeLocals(t *testing.T) {
testMergeLocalswrapper(t, simd.Int64x4.Add)
}
//go:noinline
func forceSpill() {}
func testMergeLocalswrapper(t *testing.T, op func(simd.Int64x4, simd.Int64x4) simd.Int64x4) {
t.Helper()
s0 := []int64{0, 1, 2, 3}
s1 := []int64{-1, 0, -1, 0}
want := []int64{-1, 1, 1, 3}
v := simd.LoadInt64x4Slice(s0)
m := simd.LoadInt64x4Slice(s1)
forceSpill()
got := make([]int64, 4)
gotv := op(v, m)
gotv.StoreSlice(got)
for i := range len(want) {
if !(got[i] == want[i]) {
t.Errorf("Result at %d incorrect: want %v, got %v", i, want[i], got[i])
}
}
}