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