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