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