1
2
3
4
5 package midway
6
7 import (
8 "cmd/compile/internal/syntax"
9 "cmd/compile/internal/types2"
10 )
11
12
13 type Analyzer struct {
14 pkg *types2.Package
15 info *types2.Info
16 dependentObj map[types2.Object]bool
17 visited map[types2.Type]bool
18 inSimd bool
19 }
20
21 func NewAnalyzer(pkg *types2.Package, info *types2.Info) *Analyzer {
22 return &Analyzer{
23 pkg: pkg,
24 info: info,
25 dependentObj: make(map[types2.Object]bool),
26 visited: make(map[types2.Type]bool),
27 inSimd: pkg.Path() == simdPkg,
28 }
29 }
30
31
32 func (a *Analyzer) Analyze(files []*syntax.File) bool {
33
34 for _, obj := range a.info.Defs {
35 if obj != nil {
36 a.markIfDependent(obj)
37 }
38 }
39 for _, obj := range a.info.Uses {
40 if obj != nil {
41 a.markIfDependent(obj)
42 }
43 }
44
45
46 changed := true
47 for changed {
48 changed = false
49 for _, file := range files {
50 for _, decl := range file.DeclList {
51 if fn, ok := decl.(*syntax.FuncDecl); ok {
52 if fn.Name == nil {
53 continue
54 }
55 obj := a.info.Defs[fn.Name]
56 if obj == nil || a.dependentObj[obj] {
57 continue
58 }
59
60 if a.hasBodyDependency(fn) {
61 a.dependentObj[obj] = true
62 changed = true
63 }
64 }
65 }
66 }
67 }
68
69 return len(a.dependentObj) > 0
70 }
71
72 func (a *Analyzer) hasBodyDependency(fn *syntax.FuncDecl) bool {
73 if fn.Body == nil {
74 return false
75 }
76
77 found := false
78 syntax.Inspect(fn.Body, func(n syntax.Node) bool {
79 if found {
80 return false
81 }
82 if id, ok := n.(*syntax.Name); ok {
83 obj := a.info.Uses[id]
84 if obj == nil {
85 obj = a.info.Defs[id]
86 }
87 if obj != nil {
88 if _, isFunc := obj.(*types2.Func); !isFunc {
89 if a.dependentObj[obj] {
90 found = true
91 return false
92 }
93 } else {
94 sig := obj.Type().(*types2.Signature)
95 if a.HasDependentSignature(sig) {
96 found = true
97 return false
98 }
99 }
100 if a.isDependentType(obj.Type()) {
101 found = true
102 return false
103 }
104 if isBaseSimdTypeObj(obj) {
105 found = true
106 return false
107 }
108 }
109 }
110 return true
111 })
112 return found
113 }
114
115 func (a *Analyzer) markIfDependent(obj types2.Object) bool {
116 if a.dependentObj[obj] {
117 return true
118 }
119
120 isDep := false
121 switch obj := obj.(type) {
122 case *types2.Var:
123 if obj.Pkg() == a.pkg && obj.Parent() == a.pkg.Scope() {
124 isDep = a.isDependentType(obj.Type())
125 }
126 case *types2.TypeName:
127 isDep = a.isDependentType(obj.Type())
128 case *types2.Func:
129 sig := obj.Type().(*types2.Signature)
130 if a.HasDependentSignature(sig) {
131
132
133 if rcv := sig.Recv(); rcv == nil {
134 isDep = true
135 } else if named, ok := rcv.Type().(*types2.Named); !ok || !isBaseSimdType(named) {
136 isDep = true
137 }
138 }
139 }
140
141
142 if isBaseSimdTypeObj(obj) {
143 isDep = true
144 }
145
146 if isDep {
147 a.dependentObj[obj] = true
148 }
149 return isDep
150 }
151
152 func (a *Analyzer) isDependentType(t types2.Type) bool {
153 return a.checkTypeRecursive(t)
154 }
155
156 func (a *Analyzer) checkTypeRecursive(t types2.Type) bool {
157 if t == nil {
158 return false
159 }
160 if b, ok := a.visited[t]; ok {
161 return b
162 }
163 a.visited[t] = false
164
165 memo := func(b bool) bool {
166 a.visited[t] = b
167 return b
168 }
169
170
171 if named, ok := t.(*types2.Named); ok {
172 if isBaseSimdType(named) {
173 return memo(true)
174 }
175 if a.checkTypeRecursive(named.Underlying()) {
176 return memo(true)
177 }
178 }
179
180 switch t := t.(type) {
181 case *types2.Basic:
182 return false
183 case *types2.Pointer:
184 return memo(a.checkTypeRecursive(t.Elem()))
185 case *types2.Slice:
186 return memo(a.checkTypeRecursive(t.Elem()))
187 case *types2.Array:
188 return memo(a.checkTypeRecursive(t.Elem()))
189 case *types2.Map:
190 return memo(a.checkTypeRecursive(t.Key()) ||
191 a.checkTypeRecursive(t.Elem()))
192 case *types2.Chan:
193 return memo(a.checkTypeRecursive(t.Elem()))
194 case *types2.Struct:
195 for i := 0; i < t.NumFields(); i++ {
196 if a.checkTypeRecursive(t.Field(i).Type()) {
197 return memo(true)
198 }
199 }
200 case *types2.Signature:
201 return memo(a.HasDependentSignature(t))
202 case *types2.Tuple:
203 for i := 0; i < t.Len(); i++ {
204 if a.checkTypeRecursive(t.At(i).Type()) {
205 return memo(true)
206 }
207 }
208 case *types2.Alias:
209 return memo(a.checkTypeRecursive(types2.Unalias(t)))
210 }
211 return false
212 }
213
214 func isBaseSimdType(t *types2.Named) bool {
215 return isBaseSimdTypeObj(t.Obj())
216 }
217
218 func isBaseSimdTypeObj(obj types2.Object) bool {
219 if obj == nil || obj.Pkg() == nil {
220 return false
221 }
222 if obj.Pkg().Path() != simdPkg {
223 return false
224 }
225 return isSimdTypeName(obj.Name())
226 }
227
228 func (a *Analyzer) HasDependentSignature(sig *types2.Signature) bool {
229
230 return a.isDependentType(sig.Params()) ||
231 a.isDependentType(sig.Results()) ||
232 (sig.Recv() != nil && a.isDependentType(sig.Recv().Type()))
233 }
234
View as plain text