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