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 if base.Ctxt.IsFIPS() && base.Ctxt.Flag_shared {
158 return false
159 }
160 n := n.(*ir.ConvExpr)
161 val := ir.Node(n)
162 for val.Op() == ir.OCONVIFACE {
163 val = val.(*ir.ConvExpr).X
164 }
165 if val.Type().IsInterface() {
166 return val.Op() == ir.ONIL
167 }
168 if types.IsDirectIface(val.Type()) && val.Op() == ir.ONIL {
169 return true
170 }
171 return isStaticCompositeLiteral(val)
172 }
173 return false
174 }
175
176
177
178
179
180
181
182
183
184
185 type initKind uint8
186
187 const (
188 initKindStatic initKind = iota + 1
189 initKindDynamic
190 initKindLocalCode
191 )
192
193
194
195 func fixedlit(ctxt initContext, kind initKind, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) {
196 isBlank := var_ == ir.BlankNode
197 var splitnode func(ir.Node) (a ir.Node, value ir.Node)
198 switch n.Op() {
199 case ir.OARRAYLIT, ir.OSLICELIT:
200 var k int64
201 splitnode = func(r ir.Node) (ir.Node, ir.Node) {
202 if r.Op() == ir.OKEY {
203 kv := r.(*ir.KeyExpr)
204 k = typecheck.IndexConst(kv.Key)
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 value = kv.Value
376 }
377 a := ir.NewIndexExpr(base.Pos, vauto, ir.NewInt(base.Pos, index))
378 a.SetBounded(true)
379 index++
380
381
382
383 switch value.Op() {
384 case ir.OSLICELIT:
385 break
386
387 case ir.OARRAYLIT, ir.OSTRUCTLIT:
388 value := value.(*ir.CompLitExpr)
389 k := initKindDynamic
390 if vstat == nil {
391
392
393 k = initKindLocalCode
394 }
395 fixedlit(ctxt, k, value, a, init)
396 continue
397 }
398
399 if vstat != nil && ir.IsConstNode(value) {
400 continue
401 }
402
403
404 ir.SetPos(value)
405 as := ir.NewAssignStmt(base.Pos, a, value)
406 appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(as), map[string][]*ir.Name{}))
407 }
408
409
410 a = ir.NewAssignStmt(base.Pos, var_, ir.NewSliceExpr(base.Pos, ir.OSLICE, vauto, nil, nil, nil))
411 appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(a), map[string][]*ir.Name{}))
412 }
413
414 func maplit(n *ir.CompLitExpr, m ir.Node, init *ir.Nodes) {
415
416 args := []ir.Node{ir.TypeNode(n.Type()), ir.NewInt(base.Pos, n.Len+int64(len(n.List)))}
417 a := typecheck.Expr(ir.NewCallExpr(base.Pos, ir.OMAKE, nil, args)).(*ir.MakeExpr)
418 a.RType = n.RType
419 a.SetEsc(n.Esc())
420 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, m, a))
421
422 entries := n.List
423
424
425
426 for _, r := range entries {
427 r := r.(*ir.KeyExpr)
428 if !isStaticCompositeLiteral(r.Key) || !isStaticCompositeLiteral(r.Value) {
429 base.Fatalf("maplit: entry is not a literal: %v", r)
430 }
431 }
432
433 if len(entries) > 25 {
434
435
436
437 tk := types.NewArray(n.Type().Key(), int64(len(entries)))
438 te := types.NewArray(n.Type().Elem(), int64(len(entries)))
439
440
441
442
443 types.CalcSize(tk)
444 types.CalcSize(te)
445
446
447 vstatk := readonlystaticname(tk)
448 vstate := readonlystaticname(te)
449
450 datak := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil)
451 datae := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil)
452 for _, r := range entries {
453 r := r.(*ir.KeyExpr)
454 datak.List.Append(r.Key)
455 datae.List.Append(r.Value)
456 }
457 fixedlit(inInitFunction, initKindStatic, datak, vstatk, init)
458 fixedlit(inInitFunction, initKindStatic, datae, vstate, init)
459
460
461
462
463
464 i := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
465 rhs := ir.NewIndexExpr(base.Pos, vstate, i)
466 rhs.SetBounded(true)
467
468 kidx := ir.NewIndexExpr(base.Pos, vstatk, i)
469 kidx.SetBounded(true)
470
471
472 lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, kidx)).(*ir.IndexExpr)
473 base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
474 lhs.RType = n.RType
475
476 zero := ir.NewAssignStmt(base.Pos, i, ir.NewInt(base.Pos, 0))
477 cond := ir.NewBinaryExpr(base.Pos, ir.OLT, i, ir.NewInt(base.Pos, tk.NumElem()))
478 incr := ir.NewAssignStmt(base.Pos, i, ir.NewBinaryExpr(base.Pos, ir.OADD, i, ir.NewInt(base.Pos, 1)))
479
480 var body ir.Node = ir.NewAssignStmt(base.Pos, lhs, rhs)
481 body = typecheck.Stmt(body)
482 body = orderStmtInPlace(body, map[string][]*ir.Name{})
483
484 loop := ir.NewForStmt(base.Pos, nil, cond, incr, nil, false)
485 loop.Body = []ir.Node{body}
486 loop.SetInit([]ir.Node{zero})
487
488 appendWalkStmt(init, loop)
489 return
490 }
491
492
493
494
495
496
497 tmpkey := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Key())
498 tmpelem := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Elem())
499
500 for _, r := range entries {
501 r := r.(*ir.KeyExpr)
502 index, elem := r.Key, r.Value
503
504 ir.SetPos(index)
505 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpkey, index))
506
507 ir.SetPos(elem)
508 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpelem, elem))
509
510 ir.SetPos(tmpelem)
511
512
513 lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, tmpkey)).(*ir.IndexExpr)
514 base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
515 lhs.RType = n.RType
516
517 var a ir.Node = ir.NewAssignStmt(base.Pos, lhs, tmpelem)
518 a = typecheck.Stmt(a)
519 a = orderStmtInPlace(a, map[string][]*ir.Name{})
520 appendWalkStmt(init, a)
521 }
522 }
523
524 func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
525 t := n.Type()
526 switch n.Op() {
527 default:
528 base.Fatalf("anylit: not lit, op=%v node=%v", n.Op(), n)
529
530 case ir.ONAME:
531 n := n.(*ir.Name)
532 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n))
533
534 case ir.OMETHEXPR:
535 n := n.(*ir.SelectorExpr)
536 anylit(n.FuncName(), var_, init)
537
538 case ir.OPTRLIT:
539 n := n.(*ir.AddrExpr)
540 if !t.IsPtr() {
541 base.Fatalf("anylit: not ptr")
542 }
543
544 var r ir.Node
545 if n.Prealloc != nil {
546
547 r = initStackTemp(init, n.Prealloc, nil)
548 } else {
549 r = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(n.X.Type()))
550 r.SetEsc(n.Esc())
551 }
552 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, r))
553
554 var_ = ir.NewStarExpr(base.Pos, var_)
555 var_ = typecheck.AssignExpr(var_)
556 anylit(n.X, var_, init)
557
558 case ir.OSTRUCTLIT, ir.OARRAYLIT:
559 n := n.(*ir.CompLitExpr)
560 if !t.IsStruct() && !t.IsArray() {
561 base.Fatalf("anylit: not struct/array")
562 }
563
564 if isSimpleName(var_) && len(n.List) > 4 {
565
566 vstat := readonlystaticname(t)
567
568 ctxt := inInitFunction
569 if n.Op() == ir.OARRAYLIT {
570 ctxt = inNonInitFunction
571 }
572 fixedlit(ctxt, initKindStatic, n, vstat, init)
573
574
575 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, vstat))
576
577
578 fixedlit(inInitFunction, initKindDynamic, n, var_, init)
579 break
580 }
581
582 var components int64
583 if n.Op() == ir.OARRAYLIT {
584 components = t.NumElem()
585 } else {
586 components = int64(t.NumFields())
587 }
588
589 if isSimpleName(var_) || int64(len(n.List)) < components {
590 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil))
591 }
592
593 fixedlit(inInitFunction, initKindLocalCode, n, var_, init)
594
595 case ir.OSLICELIT:
596 n := n.(*ir.CompLitExpr)
597 slicelit(inInitFunction, n, var_, init)
598
599 case ir.OMAPLIT:
600 n := n.(*ir.CompLitExpr)
601 if !t.IsMap() {
602 base.Fatalf("anylit: not map")
603 }
604 maplit(n, var_, init)
605 }
606 }
607
608
609
610
611 func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool {
612 if n.X == nil || n.Y == nil {
613
614 return false
615 }
616 if n.X.Type() == nil || n.Y.Type() == nil {
617
618 return false
619 }
620 if !isSimpleName(n.X) {
621
622 return false
623 }
624 x := n.X.(*ir.Name)
625 if !types.Identical(n.X.Type(), n.Y.Type()) {
626
627 return false
628 }
629 if x.Addrtaken() {
630
631
632
633 return false
634 }
635
636 switch n.Y.Op() {
637 default:
638
639 return false
640
641 case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
642 if ir.Any(n.Y, func(y ir.Node) bool { return ir.Uses(y, x) }) {
643
644 return false
645 }
646 anylit(n.Y, n.X, init)
647 }
648
649 return true
650 }
651
652 func genAsStatic(as *ir.AssignStmt) {
653 if as.X.Type() == nil {
654 base.Fatalf("genAsStatic as.Left not typechecked")
655 }
656
657 name, offset, ok := staticinit.StaticLoc(as.X)
658 if !ok || (name.Class != ir.PEXTERN && as.X != ir.BlankNode) {
659 base.Fatalf("genAsStatic: lhs %v", as.X)
660 }
661
662 switch r := as.Y; r.Op() {
663 case ir.OLITERAL:
664 staticdata.InitConst(name, offset, r, int(r.Type().Size()))
665 return
666 case ir.OMETHEXPR:
667 r := r.(*ir.SelectorExpr)
668 staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r.FuncName()))
669 return
670 case ir.ONAME:
671 r := r.(*ir.Name)
672 if r.Offset_ != 0 {
673 base.Fatalf("genAsStatic %+v", as)
674 }
675 if r.Class == ir.PFUNC {
676 staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r))
677 return
678 }
679 }
680 base.Fatalf("genAsStatic: rhs %v", as.Y)
681 }
682
View as plain text