diff options
| -rw-r--r-- | src/cmd/compile/internal/ssagen/ssa.go | 20 | ||||
| -rw-r--r-- | src/cmd/compile/internal/test/memoverlap_test.go | 41 |
2 files changed, 55 insertions, 6 deletions
diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 849781c9ee..3da43e715e 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -1653,6 +1653,16 @@ func (s *state) stmtList(l ir.Nodes) { } } +func peelConvNop(n ir.Node) ir.Node { + if n == nil { + return n + } + for n.Op() == ir.OCONVNOP { + n = n.(*ir.ConvExpr).X + } + return n +} + // stmt converts the statement n to SSA and adds it to s. func (s *state) stmt(n ir.Node) { s.pushLine(n.Pos()) @@ -1828,12 +1838,10 @@ func (s *state) stmt(n ir.Node) { // arrays referenced are strictly smaller parts of the same base array. // If one side of the assignment is a full array, then partial overlap // can't happen. (The arrays are either disjoint or identical.) - mayOverlap := n.X.Op() == ir.ODEREF && (n.Y != nil && n.Y.Op() == ir.ODEREF) - if n.Y != nil && n.Y.Op() == ir.ODEREF { - p := n.Y.(*ir.StarExpr).X - for p.Op() == ir.OCONVNOP { - p = p.(*ir.ConvExpr).X - } + ny := peelConvNop(n.Y) + mayOverlap := n.X.Op() == ir.ODEREF && (n.Y != nil && ny.Op() == ir.ODEREF) + if ny != nil && ny.Op() == ir.ODEREF { + p := peelConvNop(ny.(*ir.StarExpr).X) if p.Op() == ir.OSPTR && p.(*ir.UnaryExpr).X.Type().IsString() { // Pointer fields of strings point to unmodifiable memory. // That memory can't overlap with the memory being written. diff --git a/src/cmd/compile/internal/test/memoverlap_test.go b/src/cmd/compile/internal/test/memoverlap_test.go new file mode 100644 index 0000000000..c53288e6bb --- /dev/null +++ b/src/cmd/compile/internal/test/memoverlap_test.go @@ -0,0 +1,41 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package test + +import "testing" + +const arrFooSize = 96 + +type arrFoo [arrFooSize]int + +//go:noinline +func badCopy(dst, src []int) { + p := (*[arrFooSize]int)(dst[:arrFooSize]) + q := (*[arrFooSize]int)(src[:arrFooSize]) + *p = arrFoo(*q) +} + +//go:noinline +func goodCopy(dst, src []int) { + p := (*[arrFooSize]int)(dst[:arrFooSize]) + q := (*[arrFooSize]int)(src[:arrFooSize]) + *p = *q +} + +func TestOverlapedMoveWithNoopIConv(t *testing.T) { + h1 := make([]int, arrFooSize+1) + h2 := make([]int, arrFooSize+1) + for i := range arrFooSize + 1 { + h1[i] = i + h2[i] = i + } + badCopy(h1[1:], h1[:arrFooSize]) + goodCopy(h2[1:], h2[:arrFooSize]) + for i := range arrFooSize + 1 { + if h1[i] != h2[i] { + t.Errorf("h1 and h2 differ at index %d, expect them to be the same", i) + } + } +} |
