1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ssa
6
7// copyelim removes all uses of OpCopy values from f.
8// A subsequent deadcode pass is needed to actually remove the copies.
9func copyelim(f *Func) {
10	// Modify all values so no arg (including args
11	// of OpCopy) is a copy.
12	for _, b := range f.Blocks {
13		for _, v := range b.Values {
14			copyelimValue(v)
15		}
16	}
17
18	// Update block control values.
19	for _, b := range f.Blocks {
20		for i, v := range b.ControlValues() {
21			if v.Op == OpCopy {
22				b.ReplaceControl(i, v.Args[0])
23			}
24		}
25	}
26
27	// Update named values.
28	for _, name := range f.Names {
29		values := f.NamedValues[name]
30		for i, v := range values {
31			if v.Op == OpCopy {
32				values[i] = v.Args[0]
33			}
34		}
35	}
36}
37
38// copySource returns the (non-copy) op which is the
39// ultimate source of v.  v must be a copy op.
40func copySource(v *Value) *Value {
41	w := v.Args[0]
42
43	// This loop is just:
44	// for w.Op == OpCopy {
45	//     w = w.Args[0]
46	// }
47	// but we take some extra care to make sure we
48	// don't get stuck in an infinite loop.
49	// Infinite copy loops may happen in unreachable code.
50	// (TODO: or can they? Needs a test.)
51	slow := w
52	var advance bool
53	for w.Op == OpCopy {
54		w = w.Args[0]
55		if w == slow {
56			w.reset(OpUnknown)
57			break
58		}
59		if advance {
60			slow = slow.Args[0]
61		}
62		advance = !advance
63	}
64
65	// The answer is w.  Update all the copies we saw
66	// to point directly to w.  Doing this update makes
67	// sure that we don't end up doing O(n^2) work
68	// for a chain of n copies.
69	for v != w {
70		x := v.Args[0]
71		v.SetArg(0, w)
72		v = x
73	}
74	return w
75}
76
77// copyelimValue ensures that no args of v are copies.
78func copyelimValue(v *Value) {
79	for i, a := range v.Args {
80		if a.Op == OpCopy {
81			v.SetArg(i, copySource(a))
82		}
83	}
84}
85