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