1
2
3
4
5
6 package deadlocals
7
8 import (
9 "cmd/compile/internal/base"
10 "cmd/compile/internal/ir"
11 "cmd/compile/internal/types"
12 "cmd/internal/src"
13 "fmt"
14 "go/constant"
15 )
16
17
18 func Funcs(fns []*ir.Func) {
19 if base.Flag.N != 0 || base.Debug.NoDeadLocals != 0 {
20 return
21 }
22
23 zero := ir.NewBasicLit(base.AutogeneratedPos, types.Types[types.TINT], constant.MakeInt64(0))
24
25 for _, fn := range fns {
26 if fn.IsClosure() {
27 continue
28 }
29
30 v := newVisitor(fn)
31 v.nodes(fn.Body)
32
33 for _, k := range v.defsKeys {
34 assigns := v.defs[k]
35 for _, as := range assigns {
36
37
38 if clo, ok := (*as.rhs).(*ir.ClosureExpr); ok && clo.Op() == ir.OCLOSURE {
39 if clo.Func.IsClosure() {
40 ir.InitLSym(clo.Func, true)
41 }
42 }
43
44 *as.lhs = ir.BlankNode
45 *as.rhs = zero
46 }
47 if len(assigns) > 0 {
48
49
50 k.Defn = nil
51 }
52 }
53 }
54 }
55
56 type visitor struct {
57 curfn *ir.Func
58
59
60 defs map[*ir.Name][]assign
61 defsKeys []*ir.Name
62
63 doNode func(ir.Node) bool
64 }
65
66 type assign struct {
67 pos src.XPos
68 lhs, rhs *ir.Node
69 }
70
71 func newVisitor(fn *ir.Func) *visitor {
72 v := &visitor{
73 curfn: fn,
74 defs: make(map[*ir.Name][]assign),
75 }
76 v.doNode = func(n ir.Node) bool {
77 v.node(n)
78 return false
79 }
80 return v
81 }
82
83 func (v *visitor) node(n ir.Node) {
84 if n == nil {
85 return
86 }
87
88 switch n.Op() {
89 default:
90 ir.DoChildrenWithHidden(n, v.doNode)
91 case ir.OCLOSURE:
92 n := n.(*ir.ClosureExpr)
93 v.nodes(n.Init())
94 for _, cv := range n.Func.ClosureVars {
95 v.node(cv)
96 }
97 v.nodes(n.Func.Body)
98
99 case ir.ODCL:
100
101 case ir.ONAME:
102 n := n.(*ir.Name)
103 n = n.Canonical()
104 if isLocal(n, false) {
105
106 s, ok := v.defs[n]
107 if !ok {
108 v.defsKeys = append(v.defsKeys, n)
109 }
110 v.defs[n] = nil
111 for _, as := range s {
112
113 v.node(*as.rhs)
114 }
115 }
116
117 case ir.OAS:
118 n := n.(*ir.AssignStmt)
119 v.assign(n.Pos(), &n.X, &n.Y, false)
120 case ir.OAS2:
121 n := n.(*ir.AssignListStmt)
122
123
124
125
126 hasNonBlank := false
127 for i := range n.Lhs {
128 if !ir.IsBlank(n.Lhs[i]) {
129 hasNonBlank = true
130 break
131 }
132 }
133 for i := range n.Lhs {
134 v.assign(n.Pos(), &n.Lhs[i], &n.Rhs[i], hasNonBlank)
135 }
136 }
137 }
138
139 func (v *visitor) nodes(list ir.Nodes) {
140 for _, n := range list {
141 v.node(n)
142 }
143 }
144
145 func hasEffects(n ir.Node) bool {
146 if n == nil {
147 return false
148 }
149 if len(n.Init()) != 0 {
150 return true
151 }
152
153 switch n.Op() {
154
155 case ir.ONAME, ir.OLITERAL, ir.ONIL, ir.OCLOSURE:
156 return false
157 }
158 return true
159 }
160
161 func (v *visitor) assign(pos src.XPos, lhs, rhs *ir.Node, blankIsNotUse bool) {
162 name, ok := (*lhs).(*ir.Name)
163 if !ok {
164 v.node(*lhs)
165 v.node(*rhs)
166 return
167 }
168 name = name.Canonical()
169
170 if isLocal(name, blankIsNotUse) && !hasEffects(*rhs) {
171 if s, ok := v.defs[name]; !ok || s != nil {
172
173 if !ok {
174 v.defsKeys = append(v.defsKeys, name)
175 }
176 v.defs[name] = append(s, assign{pos, lhs, rhs})
177 return
178 }
179 }
180
181 v.node(*rhs)
182 }
183
184 func isLocal(n *ir.Name, blankIsNotUse bool) bool {
185 if ir.IsBlank(n) {
186
187 return blankIsNotUse
188 }
189
190 switch n.Class {
191 case ir.PAUTO, ir.PPARAM:
192 return true
193 case ir.PPARAMOUT:
194 return false
195 case ir.PEXTERN, ir.PFUNC:
196 return false
197 }
198 panic(fmt.Sprintf("unexpected Class: %+v", n))
199 }
200
View as plain text