1
2
3
4
5 package walk
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/ir"
10 "cmd/compile/internal/ssa"
11 "cmd/compile/internal/staticdata"
12 "cmd/compile/internal/staticinit"
13 "cmd/compile/internal/typecheck"
14 "cmd/compile/internal/types"
15 "cmd/internal/obj"
16 )
17
18
19
20 func walkCompLit(n ir.Node, init *ir.Nodes) ir.Node {
21 if isStaticCompositeLiteral(n) && !ssa.CanSSA(n.Type()) {
22 n := n.(*ir.CompLitExpr)
23
24
25 vstat := readonlystaticname(n.Type())
26 fixedlit(inInitFunction, initKindStatic, n, vstat, init)
27 return typecheck.Expr(vstat)
28 }
29 var_ := typecheck.TempAt(base.Pos, ir.CurFunc, n.Type())
30 anylit(n, var_, init)
31 return var_
32 }
33
34
35
36
37
38
39
40
41
42
43
44 type initContext uint8
45
46 const (
47 inInitFunction initContext = iota
48 inNonInitFunction
49 )
50
51 func (c initContext) String() string {
52 if c == inInitFunction {
53 return "inInitFunction"
54 }
55 return "inNonInitFunction"
56 }
57
58
59 func readonlystaticname(t *types.Type) *ir.Name {
60 n := staticinit.StaticName(t)
61 n.MarkReadonly()
62 n.Linksym().Set(obj.AttrContentAddressable, true)
63 n.Linksym().Set(obj.AttrLocal, true)
64 return n
65 }
66
67 func isSimpleName(nn ir.Node) bool {
68 if nn.Op() != ir.ONAME || ir.IsBlank(nn) {
69 return false
70 }
71 n := nn.(*ir.Name)
72 return n.OnStack()
73 }
74
75
76 type initGenType uint8
77
78 const (
79 initDynamic initGenType = 1 << iota
80 initConst
81 )
82
83
84
85 func getdyn(n ir.Node, top bool) initGenType {
86 switch n.Op() {
87 default:
88 if ir.IsConstNode(n) {
89 return initConst
90 }
91 return initDynamic
92
93 case ir.OSLICELIT:
94 n := n.(*ir.CompLitExpr)
95 if !top {
96 return initDynamic
97 }
98 if n.Len/4 > int64(len(n.List)) {
99
100
101
102
103
104
105 return initDynamic
106 }
107
108 case ir.OARRAYLIT, ir.OSTRUCTLIT:
109 }
110 lit := n.(*ir.CompLitExpr)
111
112 var mode initGenType
113 for _, n1 := range lit.List {
114 switch n1.Op() {
115 case ir.OKEY:
116 n1 = n1.(*ir.KeyExpr).Value
117 case ir.OSTRUCTKEY:
118 n1 = n1.(*ir.StructKeyExpr).Value
119 }
120 mode |= getdyn(n1, false)
121 if mode == initDynamic|initConst {
122 break
123 }
124 }
125 return mode
126 }
127
128
129 func isStaticCompositeLiteral(n ir.Node) bool {
130 switch n.Op() {
131 case ir.OSLICELIT:
132 return false
133 case ir.OARRAYLIT:
134 n := n.(*ir.CompLitExpr)
135 for _, r := range n.List {
136 if r.Op() == ir.OKEY {
137 r = r.(*ir.KeyExpr).Value
138 }
139 if !isStaticCompositeLiteral(r) {
140 return false
141 }
142 }
143 return true
144 case ir.OSTRUCTLIT:
145 n := n.(*ir.CompLitExpr)
146 for _, r := range n.List {
147 r := r.(*ir.StructKeyExpr)
148 if !isStaticCompositeLiteral(r.Value) {
149 return false
150 }
151 }
152 return true
153 case ir.OLITERAL, ir.ONIL:
154 return true
155 case ir.OCONVIFACE:
156
157 n := n.(*ir.ConvExpr)
158 val := ir.Node(n)
159 for val.Op() == ir.OCONVIFACE {
160 val = val.(*ir.ConvExpr).X
161 }
162 if val.Type().IsInterface() {
163 return val.Op() == ir.ONIL
164 }
165 if types.IsDirectIface(val.Type()) && val.Op() == ir.ONIL {
166 return true
167 }
168 return isStaticCompositeLiteral(val)
169 }
170 return false
171 }
172
173
174
175
176
177
178
179
180
181
182 type initKind uint8
183
184 const (
185 initKindStatic initKind = iota + 1
186 initKindDynamic
187 initKindLocalCode
188 )
189
190
191
192 func fixedlit(ctxt initContext, kind initKind, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) {
193 isBlank := var_ == ir.BlankNode
194 var splitnode func(ir.Node) (a ir.Node, value ir.Node)
195 switch n.Op() {
196 case ir.OARRAYLIT, ir.OSLICELIT:
197 var k int64
198 splitnode = func(r ir.Node) (ir.Node, ir.Node) {
199 if r.Op() == ir.OKEY {
200 kv := r.(*ir.KeyExpr)
201 k = typecheck.IndexConst(kv.Key)
202 if k < 0 {
203 base.Fatalf("fixedlit: invalid index %v", kv.Key)
204 }
205 r = kv.Value
206 }
207 a := ir.NewIndexExpr(base.Pos, var_, ir.NewInt(base.Pos, k))
208 k++
209 if isBlank {
210 return ir.BlankNode, r
211 }
212 return a, r
213 }
214 case ir.OSTRUCTLIT:
215 splitnode = func(rn ir.Node) (ir.Node, ir.Node) {
216 r := rn.(*ir.StructKeyExpr)
217 if r.Sym().IsBlank() || isBlank {
218 return ir.BlankNode, r.Value
219 }
220 ir.SetPos(r)
221 return ir.NewSelectorExpr(base.Pos, ir.ODOT, var_, r.Sym()), r.Value
222 }
223 default:
224 base.Fatalf("fixedlit bad op: %v", n.Op())
225 }
226
227 for _, r := range n.List {
228 a, value := splitnode(r)
229 if a == ir.BlankNode && !staticinit.AnySideEffects(value) {
230
231 continue
232 }
233
234 switch value.Op() {
235 case ir.OSLICELIT:
236 value := value.(*ir.CompLitExpr)
237 if (kind == initKindStatic && ctxt == inNonInitFunction) || (kind == initKindDynamic && ctxt == inInitFunction) {
238 var sinit ir.Nodes
239 slicelit(ctxt, value, a, &sinit)
240 if kind == initKindStatic {
241
242
243
244
245 orderBlock(&sinit, map[string][]*ir.Name{})
246 typecheck.Stmts(sinit)
247 walkStmtList(sinit)
248 }
249 init.Append(sinit...)
250 continue
251 }
252
253 case ir.OARRAYLIT, ir.OSTRUCTLIT:
254 value := value.(*ir.CompLitExpr)
255 fixedlit(ctxt, kind, value, a, init)
256 continue
257 }
258
259 islit := ir.IsConstNode(value)
260 if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
261 continue
262 }
263
264
265 ir.SetPos(a)
266 as := ir.NewAssignStmt(base.Pos, a, value)
267 as = typecheck.Stmt(as).(*ir.AssignStmt)
268 switch kind {
269 case initKindStatic:
270 genAsStatic(as)
271 case initKindDynamic, initKindLocalCode:
272 appendWalkStmt(init, orderStmtInPlace(as, map[string][]*ir.Name{}))
273 default:
274 base.Fatalf("fixedlit: bad kind %d", kind)
275 }
276
277 }
278 }
279
280 func isSmallSliceLit(n *ir.CompLitExpr) bool {
281 if n.Op() != ir.OSLICELIT {
282 return false
283 }
284
285 return n.Type().Elem().Size() == 0 || n.Len <= ir.MaxSmallArraySize/n.Type().Elem().Size()
286 }
287
288 func slicelit(ctxt initContext, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) {
289
290 t := types.NewArray(n.Type().Elem(), n.Len)
291 types.CalcSize(t)
292
293 if ctxt == inNonInitFunction {
294
295 vstat := staticinit.StaticName(t)
296
297 fixedlit(ctxt, initKindStatic, n, vstat, init)
298 fixedlit(ctxt, initKindDynamic, n, vstat, init)
299
300
301 var_ = typecheck.AssignExpr(var_)
302 name, offset, ok := staticinit.StaticLoc(var_)
303 if !ok || name.Class != ir.PEXTERN {
304 base.Fatalf("slicelit: %v", var_)
305 }
306 staticdata.InitSlice(name, offset, vstat.Linksym(), t.NumElem())
307 return
308 }
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331 var vstat ir.Node
332
333 mode := getdyn(n, true)
334 if mode&initConst != 0 && !isSmallSliceLit(n) {
335 if ctxt == inInitFunction {
336 vstat = readonlystaticname(t)
337 } else {
338 vstat = staticinit.StaticName(t)
339 }
340 fixedlit(ctxt, initKindStatic, n, vstat, init)
341 }
342
343
344 vauto := typecheck.TempAt(base.Pos, ir.CurFunc, types.NewPtr(t))
345
346
347 var a ir.Node
348 if x := n.Prealloc; x != nil {
349
350 if !types.Identical(t, x.Type()) {
351 panic("dotdotdot base type does not match order's assigned type")
352 }
353 a = initStackTemp(init, x, vstat)
354 } else if n.Esc() == ir.EscNone {
355 a = initStackTemp(init, typecheck.TempAt(base.Pos, ir.CurFunc, t), vstat)
356 } else {
357 a = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(t))
358 }
359 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, vauto, a))
360
361 if vstat != nil && n.Prealloc == nil && n.Esc() != ir.EscNone {
362
363
364
365 a = ir.NewStarExpr(base.Pos, vauto)
366 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, a, vstat))
367 }
368
369
370 var index int64
371 for _, value := range n.List {
372 if value.Op() == ir.OKEY {
373 kv := value.(*ir.KeyExpr)
374 index = typecheck.IndexConst(kv.Key)
375 if index < 0 {
376 base.Fatalf("slicelit: invalid index %v", kv.Key)
377 }
378 value = kv.Value
379 }
380 a := ir.NewIndexExpr(base.Pos, vauto, ir.NewInt(base.Pos, index))
381 a.SetBounded(true)
382 index++
383
384
385
386 switch value.Op() {
387 case ir.OSLICELIT:
388 break
389
390 case ir.OARRAYLIT, ir.OSTRUCTLIT:
391 value := value.(*ir.CompLitExpr)
392 k := initKindDynamic
393 if vstat == nil {
394
395
396 k = initKindLocalCode
397 }
398 fixedlit(ctxt, k, value, a, init)
399 continue
400 }
401
402 if vstat != nil && ir.IsConstNode(value) {
403 continue
404 }
405
406
407 ir.SetPos(value)
408 as := ir.NewAssignStmt(base.Pos, a, value)
409 appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(as), map[string][]*ir.Name{}))
410 }
411
412
413 a = ir.NewAssignStmt(base.Pos, var_, ir.NewSliceExpr(base.Pos, ir.OSLICE, vauto, nil, nil, nil))
414 appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(a), map[string][]*ir.Name{}))
415 }
416
417 func maplit(n *ir.CompLitExpr, m ir.Node, init *ir.Nodes) {
418
419 args := []ir.Node{ir.TypeNode(n.Type()), ir.NewInt(base.Pos, n.Len+int64(len(n.List)))}
420 a := typecheck.Expr(ir.NewCallExpr(base.Pos, ir.OMAKE, nil, args)).(*ir.MakeExpr)
421 a.RType = n.RType
422 a.SetEsc(n.Esc())
423 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, m, a))
424
425 entries := n.List
426
427
428
429 for _, r := range entries {
430 r := r.(*ir.KeyExpr)
431 if !isStaticCompositeLiteral(r.Key) || !isStaticCompositeLiteral(r.Value) {
432 base.Fatalf("maplit: entry is not a literal: %v", r)
433 }
434 }
435
436 if len(entries) > 25 {
437
438
439
440 tk := types.NewArray(n.Type().Key(), int64(len(entries)))
441 te := types.NewArray(n.Type().Elem(), int64(len(entries)))
442
443
444
445
446 types.CalcSize(tk)
447 types.CalcSize(te)
448
449
450 vstatk := readonlystaticname(tk)
451 vstate := readonlystaticname(te)
452
453 datak := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil)
454 datae := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil)
455 for _, r := range entries {
456 r := r.(*ir.KeyExpr)
457 datak.List.Append(r.Key)
458 datae.List.Append(r.Value)
459 }
460 fixedlit(inInitFunction, initKindStatic, datak, vstatk, init)
461 fixedlit(inInitFunction, initKindStatic, datae, vstate, init)
462
463
464
465
466
467 i := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
468 rhs := ir.NewIndexExpr(base.Pos, vstate, i)
469 rhs.SetBounded(true)
470
471 kidx := ir.NewIndexExpr(base.Pos, vstatk, i)
472 kidx.SetBounded(true)
473
474
475 lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, kidx)).(*ir.IndexExpr)
476 base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
477 lhs.RType = n.RType
478
479 zero := ir.NewAssignStmt(base.Pos, i, ir.NewInt(base.Pos, 0))
480 cond := ir.NewBinaryExpr(base.Pos, ir.OLT, i, ir.NewInt(base.Pos, tk.NumElem()))
481 incr := ir.NewAssignStmt(base.Pos, i, ir.NewBinaryExpr(base.Pos, ir.OADD, i, ir.NewInt(base.Pos, 1)))
482
483 var body ir.Node = ir.NewAssignStmt(base.Pos, lhs, rhs)
484 body = typecheck.Stmt(body)
485 body = orderStmtInPlace(body, map[string][]*ir.Name{})
486
487 loop := ir.NewForStmt(base.Pos, nil, cond, incr, nil, false)
488 loop.Body = []ir.Node{body}
489 loop.SetInit([]ir.Node{zero})
490
491 appendWalkStmt(init, loop)
492 return
493 }
494
495
496
497
498
499
500 tmpkey := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Key())
501 tmpelem := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Elem())
502
503 for _, r := range entries {
504 r := r.(*ir.KeyExpr)
505 index, elem := r.Key, r.Value
506
507 ir.SetPos(index)
508 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpkey, index))
509
510 ir.SetPos(elem)
511 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpelem, elem))
512
513 ir.SetPos(tmpelem)
514
515
516 lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, tmpkey)).(*ir.IndexExpr)
517 base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
518 lhs.RType = n.RType
519
520 var a ir.Node = ir.NewAssignStmt(base.Pos, lhs, tmpelem)
521 a = typecheck.Stmt(a)
522 a = orderStmtInPlace(a, map[string][]*ir.Name{})
523 appendWalkStmt(init, a)
524 }
525 }
526
527 func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
528 t := n.Type()
529 switch n.Op() {
530 default:
531 base.Fatalf("anylit: not lit, op=%v node=%v", n.Op(), n)
532
533 case ir.ONAME:
534 n := n.(*ir.Name)
535 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n))
536
537 case ir.OMETHEXPR:
538 n := n.(*ir.SelectorExpr)
539 anylit(n.FuncName(), var_, init)
540
541 case ir.OPTRLIT:
542 n := n.(*ir.AddrExpr)
543 if !t.IsPtr() {
544 base.Fatalf("anylit: not ptr")
545 }
546
547 var r ir.Node
548 if n.Prealloc != nil {
549
550 r = initStackTemp(init, n.Prealloc, nil)
551 } else {
552 r = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(n.X.Type()))
553 r.SetEsc(n.Esc())
554 }
555 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, r))
556
557 var_ = ir.NewStarExpr(base.Pos, var_)
558 var_ = typecheck.AssignExpr(var_)
559 anylit(n.X, var_, init)
560
561 case ir.OSTRUCTLIT, ir.OARRAYLIT:
562 n := n.(*ir.CompLitExpr)
563 if !t.IsStruct() && !t.IsArray() {
564 base.Fatalf("anylit: not struct/array")
565 }
566
567 if isSimpleName(var_) && len(n.List) > 4 {
568
569 vstat := readonlystaticname(t)
570
571 ctxt := inInitFunction
572 if n.Op() == ir.OARRAYLIT {
573 ctxt = inNonInitFunction
574 }
575 fixedlit(ctxt, initKindStatic, n, vstat, init)
576
577
578 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, vstat))
579
580
581 fixedlit(inInitFunction, initKindDynamic, n, var_, init)
582 break
583 }
584
585 var components int64
586 if n.Op() == ir.OARRAYLIT {
587 components = t.NumElem()
588 } else {
589 components = int64(t.NumFields())
590 }
591
592 if isSimpleName(var_) || int64(len(n.List)) < components {
593 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil))
594 }
595
596 fixedlit(inInitFunction, initKindLocalCode, n, var_, init)
597
598 case ir.OSLICELIT:
599 n := n.(*ir.CompLitExpr)
600 slicelit(inInitFunction, n, var_, init)
601
602 case ir.OMAPLIT:
603 n := n.(*ir.CompLitExpr)
604 if !t.IsMap() {
605 base.Fatalf("anylit: not map")
606 }
607 maplit(n, var_, init)
608 }
609 }
610
611
612
613
614 func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool {
615 if n.X == nil || n.Y == nil {
616
617 return false
618 }
619 if n.X.Type() == nil || n.Y.Type() == nil {
620
621 return false
622 }
623 if !isSimpleName(n.X) {
624
625 return false
626 }
627 x := n.X.(*ir.Name)
628 if !types.Identical(n.X.Type(), n.Y.Type()) {
629
630 return false
631 }
632 if x.Addrtaken() {
633
634
635
636 return false
637 }
638
639 switch n.Y.Op() {
640 default:
641
642 return false
643
644 case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
645 if ir.Any(n.Y, func(y ir.Node) bool { return ir.Uses(y, x) }) {
646
647 return false
648 }
649 anylit(n.Y, n.X, init)
650 }
651
652 return true
653 }
654
655 func genAsStatic(as *ir.AssignStmt) {
656 if as.X.Type() == nil {
657 base.Fatalf("genAsStatic as.Left not typechecked")
658 }
659
660 name, offset, ok := staticinit.StaticLoc(as.X)
661 if !ok || (name.Class != ir.PEXTERN && as.X != ir.BlankNode) {
662 base.Fatalf("genAsStatic: lhs %v", as.X)
663 }
664
665 switch r := as.Y; r.Op() {
666 case ir.OLITERAL:
667 staticdata.InitConst(name, offset, r, int(r.Type().Size()))
668 return
669 case ir.OMETHEXPR:
670 r := r.(*ir.SelectorExpr)
671 staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r.FuncName()))
672 return
673 case ir.ONAME:
674 r := r.(*ir.Name)
675 if r.Offset_ != 0 {
676 base.Fatalf("genAsStatic %+v", as)
677 }
678 if r.Class == ir.PFUNC {
679 staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r))
680 return
681 }
682 }
683 base.Fatalf("genAsStatic: rhs %v", as.Y)
684 }
685
View as plain text