From 1440ff70362f85c86b54b5c428fd95cb6cb35d91 Mon Sep 17 00:00:00 2001 From: Junyang Shao Date: Thu, 10 Jul 2025 22:04:21 +0000 Subject: [PATCH] [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 Reviewed-by: David Chase --- src/cmd/compile/internal/ssa/func.go | 8 ++++++++ src/simd/simd_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 5736f0b812..01ce89cf47 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -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 } diff --git a/src/simd/simd_test.go b/src/simd/simd_test.go index ebe241c467..36923319ff 100644 --- a/src/simd/simd_test.go +++ b/src/simd/simd_test.go @@ -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]) + } + } +} -- 2.52.0