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