// reaches stores then we delete all the stores. The other operations will then
// be eliminated by the dead code elimination pass.
func elimDeadAutosGeneric(f *Func) {
- addr := make(map[*Value]*ir.Name) // values that the address of the auto reaches
- elim := make(map[*Value]*ir.Name) // values that could be eliminated if the auto is
- var used ir.NameSet // used autos that must be kept
+ addr := make(map[*Value]*ir.Name) // values that the address of the auto reaches
+ elim := make(map[*Value]*ir.Name) // values that could be eliminated if the auto is
+ move := make(map[*ir.Name]ir.NameSet) // for a (Move &y &x _) and y is unused, move[y].Add(x)
+ var used ir.NameSet // used autos that must be kept
+
+ // Adds a name to used and, when it is the target of a move, also
+ // propagates the used state to its source.
+ var usedAdd func(n *ir.Name) bool
+ usedAdd = func(n *ir.Name) bool {
+ if used.Has(n) {
+ return false
+ }
+ used.Add(n)
+ if s := move[n]; s != nil {
+ delete(move, n)
+ for n := range s {
+ usedAdd(n)
+ }
+ }
+ return true
+ }
// visit the value and report whether any of the maps are updated
visit := func(v *Value) (changed bool) {
if !ok || (n.Class != ir.PAUTO && !isABIInternalParam(f, n)) {
return
}
- if !used.Has(n) {
- used.Add(n)
- changed = true
- }
+ changed = usedAdd(n) || changed
return
case OpStore, OpMove, OpZero:
// v should be eliminated if we eliminate the auto.
if v.Type.IsMemory() || v.Type.IsFlags() || v.Op == OpPhi || v.MemoryArg() != nil {
for _, a := range args {
if n, ok := addr[a]; ok {
- if !used.Has(n) {
- used.Add(n)
- changed = true
+ // If the addr of n is used by an OpMove as its source arg,
+ // and the OpMove's target arg is the addr of a unused name,
+ // then temporarily treat n as unused, and record in move map.
+ if nam, ok := elim[v]; ok && v.Op == OpMove && !used.Has(nam) {
+ if used.Has(n) {
+ continue
+ }
+ s := move[nam]
+ if s == nil {
+ s = ir.NameSet{}
+ move[nam] = s
+ }
+ s.Add(n)
+ continue
}
+ changed = usedAdd(n) || changed
}
}
return
// Propagate any auto addresses through v.
var node *ir.Name
for _, a := range args {
- if n, ok := addr[a]; ok && !used.Has(n) {
+ if n, ok := addr[a]; ok {
if node == nil {
- node = n
- } else if node != n {
+ if !used.Has(n) {
+ node = n
+ }
+ } else {
+ if node == n {
+ continue
+ }
// Most of the time we only see one pointer
// reaching an op, but some ops can take
// multiple pointers (e.g. NeqPtr, Phi etc.).
// This is rare, so just propagate the first
// value to keep things simple.
- used.Add(n)
- changed = true
+ changed = usedAdd(n) || changed
}
}
}
}
if addr[v] != node {
// This doesn't happen in practice, but catch it just in case.
- used.Add(node)
- changed = true
+ changed = usedAdd(node) || changed
}
return
}
}
// keep the auto if its address reaches a control value
for _, c := range b.ControlValues() {
- if n, ok := addr[c]; ok && !used.Has(n) {
- used.Add(n)
- changed = true
+ if n, ok := addr[c]; ok {
+ changed = usedAdd(n) || changed
}
}
}
--- /dev/null
+// Copyright 2025 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"
+
+var (
+ n = [16]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
+ m = [16]int{2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32}
+)
+
+func TestEqual(t *testing.T) {
+ if r := move2(n, m, 0); r != n {
+ t.Fatalf("%v != %v", r, n)
+ }
+ if r := move2(n, m, 1); r != m {
+ t.Fatalf("%v != %v", r, m)
+ }
+ if r := move2p(n, m, 0); r != n {
+ t.Fatalf("%v != %v", r, n)
+ }
+ if r := move2p(n, m, 1); r != m {
+ t.Fatalf("%v != %v", r, m)
+ }
+}
+
+//go:noinline
+func move2(a, b [16]int, c int) [16]int {
+ e := a
+ f := b
+ var d [16]int
+ if c%2 == 0 {
+ d = e
+ } else {
+ d = f
+ }
+ r := d
+ return r
+}
+
+//go:noinline
+func move2p(a, b [16]int, c int) [16]int {
+ e := a
+ f := b
+ var p *[16]int
+ if c%2 == 0 {
+ p = &e
+ } else {
+ p = &f
+ }
+ r := *p
+ return r
+}
return ok
}
+func AccessStringIntArray2(m map[string][16]int, k string) bool {
+ // amd64:-"MOVUPS"
+ _, ok := m[k]
+ return ok
+}
+
+type Struct struct {
+ A, B, C, D, E, F, G, H, I, J int
+}
+
+func AccessStringStruct2(m map[string]Struct, k string) bool {
+ // amd64:-"MOVUPS"
+ _, ok := m[k]
+ return ok
+}
+
+func AccessIntArrayLarge2(m map[int][512]int, k int) bool {
+ // amd64:-"REP",-"MOVSQ"
+ _, ok := m[k]
+ return ok
+}
+
// ------------------- //
// String Conversion //
// ------------------- //