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