aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/ssagen/ssa.go20
-rw-r--r--src/cmd/compile/internal/test/memoverlap_test.go41
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)
+ }
+ }
+}