1
2
3
4
5 package walk
6
7 import (
8 "fmt"
9 "internal/abi"
10
11 "cmd/compile/internal/base"
12 "cmd/compile/internal/ir"
13 "cmd/compile/internal/rttype"
14 "cmd/compile/internal/ssagen"
15 "cmd/compile/internal/typecheck"
16 "cmd/compile/internal/types"
17 "cmd/internal/src"
18 )
19
20
21 const tmpstringbufsize = 32
22
23 func Walk(fn *ir.Func) {
24 ir.CurFunc = fn
25
26
27
28
29 staticValues = findStaticValues(fn)
30 defer func() { staticValues = nil }()
31
32 errorsBefore := base.Errors()
33 order(fn)
34 if base.Errors() > errorsBefore {
35 return
36 }
37
38 if base.Flag.W != 0 {
39 s := fmt.Sprintf("\nbefore walk %v", ir.CurFunc.Sym())
40 ir.DumpList(s, ir.CurFunc.Body)
41 }
42
43 walkStmtList(ir.CurFunc.Body)
44 if base.Flag.W != 0 {
45 s := fmt.Sprintf("after walk %v", ir.CurFunc.Sym())
46 ir.DumpList(s, ir.CurFunc.Body)
47 }
48
49
50 for _, n := range fn.Dcl {
51 types.CalcSize(n.Type())
52 }
53 }
54
55
56 func walkRecv(n *ir.UnaryExpr) ir.Node {
57 if n.Typecheck() == 0 {
58 base.Fatalf("missing typecheck: %+v", n)
59 }
60 init := ir.TakeInit(n)
61
62 n.X = walkExpr(n.X, &init)
63 call := walkExpr(mkcall1(chanfn("chanrecv1", 2, n.X.Type()), nil, &init, n.X, typecheck.NodNil()), &init)
64 return ir.InitExpr(init, call)
65 }
66
67 func convas(n *ir.AssignStmt, init *ir.Nodes) *ir.AssignStmt {
68 if n.Op() != ir.OAS {
69 base.Fatalf("convas: not OAS %v", n.Op())
70 }
71 n.SetTypecheck(1)
72
73 if n.X == nil || n.Y == nil {
74 return n
75 }
76
77 lt := n.X.Type()
78 rt := n.Y.Type()
79 if lt == nil || rt == nil {
80 return n
81 }
82
83 if ir.IsBlank(n.X) {
84 n.Y = typecheck.DefaultLit(n.Y, nil)
85 return n
86 }
87
88 if !types.Identical(lt, rt) {
89 n.Y = typecheck.AssignConv(n.Y, lt, "assignment")
90 n.Y = walkExpr(n.Y, init)
91 }
92 types.CalcSize(n.Y.Type())
93
94 return n
95 }
96
97 func vmkcall(fn ir.Node, t *types.Type, init *ir.Nodes, va []ir.Node) *ir.CallExpr {
98 if init == nil {
99 base.Fatalf("mkcall with nil init: %v", fn)
100 }
101 if fn.Type() == nil || fn.Type().Kind() != types.TFUNC {
102 base.Fatalf("mkcall %v %v", fn, fn.Type())
103 }
104
105 n := fn.Type().NumParams()
106 if n != len(va) {
107 base.Fatalf("vmkcall %v needs %v args got %v", fn, n, len(va))
108 }
109
110 call := typecheck.Call(base.Pos, fn, va, false).(*ir.CallExpr)
111 call.SetType(t)
112 return walkExpr(call, init).(*ir.CallExpr)
113 }
114
115 func mkcall(name string, t *types.Type, init *ir.Nodes, args ...ir.Node) *ir.CallExpr {
116 return vmkcall(typecheck.LookupRuntime(name), t, init, args)
117 }
118
119 func mkcallstmt(name string, args ...ir.Node) ir.Node {
120 return mkcallstmt1(typecheck.LookupRuntime(name), args...)
121 }
122
123 func mkcall1(fn ir.Node, t *types.Type, init *ir.Nodes, args ...ir.Node) *ir.CallExpr {
124 return vmkcall(fn, t, init, args)
125 }
126
127 func mkcallstmt1(fn ir.Node, args ...ir.Node) ir.Node {
128 var init ir.Nodes
129 n := vmkcall(fn, nil, &init, args)
130 if len(init) == 0 {
131 return n
132 }
133 init.Append(n)
134 return ir.NewBlockStmt(n.Pos(), init)
135 }
136
137 func chanfn(name string, n int, t *types.Type) ir.Node {
138 if !t.IsChan() {
139 base.Fatalf("chanfn %v", t)
140 }
141 switch n {
142 case 1:
143 return typecheck.LookupRuntime(name, t.Elem())
144 case 2:
145 return typecheck.LookupRuntime(name, t.Elem(), t.Elem())
146 }
147 base.Fatalf("chanfn %d", n)
148 return nil
149 }
150
151 func mapfn(name string, t *types.Type, isfat bool) ir.Node {
152 if !t.IsMap() {
153 base.Fatalf("mapfn %v", t)
154 }
155 if mapfast(t) == mapslow || isfat {
156 return typecheck.LookupRuntime(name, t.Key(), t.Elem(), t.Key(), t.Elem())
157 }
158 return typecheck.LookupRuntime(name, t.Key(), t.Elem(), t.Elem())
159 }
160
161 func mapfndel(name string, t *types.Type) ir.Node {
162 if !t.IsMap() {
163 base.Fatalf("mapfn %v", t)
164 }
165 if mapfast(t) == mapslow {
166 return typecheck.LookupRuntime(name, t.Key(), t.Elem(), t.Key())
167 }
168 return typecheck.LookupRuntime(name, t.Key(), t.Elem())
169 }
170
171 const (
172 mapslow = iota
173 mapfast32
174 mapfast32ptr
175 mapfast64
176 mapfast64ptr
177 mapfaststr
178 nmapfast
179 )
180
181 type mapnames [nmapfast]string
182
183 func mkmapnames(base string, ptr string) mapnames {
184 return mapnames{base, base + "_fast32", base + "_fast32" + ptr, base + "_fast64", base + "_fast64" + ptr, base + "_faststr"}
185 }
186
187 var mapaccess = mkmapnames("mapaccess2", "")
188 var mapassign = mkmapnames("mapassign", "ptr")
189 var mapdelete = mkmapnames("mapdelete", "")
190
191 func mapfast(t *types.Type) int {
192 if t.Elem().Size() > abi.MapMaxElemBytes {
193 return mapslow
194 }
195 switch algType(t.Key()) {
196 case types.AMEM32:
197 if !t.Key().HasPointers() {
198 return mapfast32
199 }
200 if types.PtrSize == 4 {
201 return mapfast32ptr
202 }
203 base.Fatalf("small pointer %v", t.Key())
204 case types.AMEM64:
205 if !t.Key().HasPointers() {
206 return mapfast64
207 }
208 if types.PtrSize == 8 {
209 return mapfast64ptr
210 }
211
212
213 case types.ASTRING:
214 return mapfaststr
215 }
216 return mapslow
217 }
218
219
220
221 func algType(t *types.Type) types.AlgKind {
222 a := types.AlgType(t)
223 if a == types.AMEM {
224 if t.Alignment() < int64(base.Ctxt.Arch.Alignment) && t.Alignment() < t.Size() {
225
226
227 return a
228 }
229 switch t.Size() {
230 case 0:
231 return types.AMEM0
232 case 1:
233 return types.AMEM8
234 case 2:
235 return types.AMEM16
236 case 4:
237 return types.AMEM32
238 case 8:
239 return types.AMEM64
240 case 16:
241 return types.AMEM128
242 }
243 }
244
245 return a
246 }
247
248 func walkAppendArgs(n *ir.CallExpr, init *ir.Nodes) {
249 walkExprListSafe(n.Args, init)
250
251
252
253
254 ls := n.Args
255 for i1, n1 := range ls {
256 ls[i1] = cheapExpr(n1, init)
257 }
258 }
259
260
261 func appendWalkStmt(init *ir.Nodes, stmt ir.Node) {
262 op := stmt.Op()
263 n := typecheck.Stmt(stmt)
264 if op == ir.OAS || op == ir.OAS2 {
265
266
267
268
269 n = walkExpr(n, init)
270 } else {
271 n = walkStmt(n)
272 }
273 init.Append(n)
274 }
275
276
277
278 const maxOpenDefers = 8
279
280
281
282 func backingArrayPtrLen(n ir.Node) (ptr, length ir.Node) {
283 var init ir.Nodes
284 c := cheapExpr(n, &init)
285 if c != n || len(init) != 0 {
286 base.Fatalf("backingArrayPtrLen not cheap: %v", n)
287 }
288 ptr = ir.NewUnaryExpr(base.Pos, ir.OSPTR, n)
289 if n.Type().IsString() {
290 ptr.SetType(types.Types[types.TUINT8].PtrTo())
291 } else {
292 ptr.SetType(n.Type().Elem().PtrTo())
293 }
294 ptr.SetTypecheck(1)
295 length = ir.NewUnaryExpr(base.Pos, ir.OLEN, n)
296 length.SetType(types.Types[types.TINT])
297 length.SetTypecheck(1)
298 return ptr, length
299 }
300
301
302
303
304 func mayCall(n ir.Node) bool {
305
306
307
308
309
310 if n.Op() == ir.OLITERAL {
311 return false
312 }
313
314
315 if base.Flag.Cfg.Instrumenting {
316 return true
317 }
318
319 isSoftFloat := func(typ *types.Type) bool {
320 return types.IsFloat[typ.Kind()] || types.IsComplex[typ.Kind()]
321 }
322
323 return ir.Any(n, func(n ir.Node) bool {
324
325
326 if len(n.Init()) != 0 {
327 base.FatalfAt(n.Pos(), "mayCall %+v", n)
328 }
329
330 switch n.Op() {
331 default:
332 base.FatalfAt(n.Pos(), "mayCall %+v", n)
333
334 case ir.OCALLFUNC, ir.OCALLINTER,
335 ir.OUNSAFEADD, ir.OUNSAFESLICE:
336 return true
337
338 case ir.OINDEX, ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR,
339 ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODYNAMICDOTTYPE, ir.ODIV, ir.OMOD,
340 ir.OSLICE2ARR, ir.OSLICE2ARRPTR:
341
342
343 return true
344
345 case ir.OANDAND, ir.OOROR:
346 n := n.(*ir.LogicalExpr)
347
348
349
350
351 return len(n.Y.Init()) != 0
352
353
354
355 case ir.OADD, ir.OSUB, ir.OMUL, ir.ONEG:
356 return ssagen.Arch.SoftFloat && isSoftFloat(n.Type())
357 case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT:
358 n := n.(*ir.BinaryExpr)
359 return ssagen.Arch.SoftFloat && isSoftFloat(n.X.Type())
360 case ir.OCONV:
361 n := n.(*ir.ConvExpr)
362 return ssagen.Arch.SoftFloat && (isSoftFloat(n.Type()) || isSoftFloat(n.X.Type()))
363
364 case ir.OMIN, ir.OMAX:
365
366 return n.Type().IsString() || n.Type().IsFloat()
367
368 case ir.OLITERAL, ir.ONIL, ir.ONAME, ir.OLINKSYMOFFSET, ir.OMETHEXPR,
369 ir.OAND, ir.OANDNOT, ir.OLSH, ir.OOR, ir.ORSH, ir.OXOR, ir.OCOMPLEX, ir.OMAKEFACE,
370 ir.OADDR, ir.OBITNOT, ir.ONOT, ir.OPLUS,
371 ir.OCAP, ir.OIMAG, ir.OLEN, ir.OREAL,
372 ir.OCONVNOP, ir.ODOT,
373 ir.OCFUNC, ir.OIDATA, ir.OITAB, ir.OSPTR,
374 ir.OBYTES2STRTMP, ir.OGETG, ir.OGETCALLERSP, ir.OSLICEHEADER, ir.OSTRINGHEADER:
375
376
377 }
378
379 return false
380 })
381 }
382
383
384 func itabType(itab ir.Node) ir.Node {
385 if itabTypeField == nil {
386
387 itabTypeField = runtimeField("Type", rttype.ITab.OffsetOf("Type"), types.NewPtr(types.Types[types.TUINT8]))
388 }
389 return boundedDotPtr(base.Pos, itab, itabTypeField)
390 }
391
392 var itabTypeField *types.Field
393
394
395
396 func boundedDotPtr(pos src.XPos, ptr ir.Node, field *types.Field) *ir.SelectorExpr {
397 sel := ir.NewSelectorExpr(pos, ir.ODOTPTR, ptr, field.Sym)
398 sel.Selection = field
399 sel.SetType(field.Type)
400 sel.SetTypecheck(1)
401 sel.SetBounded(true)
402 return sel
403 }
404
405 func runtimeField(name string, offset int64, typ *types.Type) *types.Field {
406 f := types.NewField(src.NoXPos, ir.Pkgs.Runtime.Lookup(name), typ)
407 f.Offset = offset
408 return f
409 }
410
411
412
413
414 func ifaceData(pos src.XPos, n ir.Node, t *types.Type) ir.Node {
415 if t.IsInterface() {
416 base.Fatalf("ifaceData interface: %v", t)
417 }
418 ptr := ir.NewUnaryExpr(pos, ir.OIDATA, n)
419 if types.IsDirectIface(t) {
420 ptr.SetType(t)
421 ptr.SetTypecheck(1)
422 return ptr
423 }
424 ptr.SetType(types.NewPtr(t))
425 ptr.SetTypecheck(1)
426 ind := ir.NewStarExpr(pos, ptr)
427 ind.SetType(t)
428 ind.SetTypecheck(1)
429 ind.SetBounded(true)
430 return ind
431 }
432
433
434
435
436
437
438
439
440
441
442 func staticValue(n ir.Node) ir.Node {
443 if staticValues == nil {
444 base.Fatalf("staticValues is nil. staticValue called outside of walk.Walk?")
445 }
446 return staticValues[n]
447 }
448
449
450 var staticValues map[ir.Node]ir.Node
451
452
453 func findStaticValues(fn *ir.Func) map[ir.Node]ir.Node {
454
455
456
457
458 ro := &ir.ReassignOracle{}
459 ro.Init(fn)
460 m := make(map[ir.Node]ir.Node)
461 ir.Visit(fn, func(n ir.Node) {
462 if n.Op() == ir.OCONVIFACE {
463 x := n.(*ir.ConvExpr).X
464 v := ro.StaticValue(x)
465 if v != nil && v != x {
466 m[x] = v
467 }
468 }
469 })
470 return m
471 }
472
View as plain text