Source file src/pkg/cmd/compile/internal/gc/sinit.go
1
2
3
4
5 package gc
6
7 import (
8 "cmd/compile/internal/types"
9 "fmt"
10 )
11
12 type InitEntry struct {
13 Xoffset int64
14 Expr *Node
15 }
16
17 type InitPlan struct {
18 E []InitEntry
19 }
20
21
22
23
24
25 type InitSchedule struct {
26
27
28 out []*Node
29
30 initplans map[*Node]*InitPlan
31 inittemps map[*Node]*Node
32 }
33
34 func (s *InitSchedule) append(n *Node) {
35 s.out = append(s.out, n)
36 }
37
38
39 func (s *InitSchedule) staticInit(n *Node) {
40 if !s.tryStaticInit(n) {
41 if Debug['%'] != 0 {
42 Dump("nonstatic", n)
43 }
44 s.append(n)
45 }
46 }
47
48
49
50 func (s *InitSchedule) tryStaticInit(n *Node) bool {
51
52
53
54
55
56 if n.Op != OAS {
57 return false
58 }
59 if n.Left.isBlank() && candiscard(n.Right) {
60 return true
61 }
62 lno := setlineno(n)
63 defer func() { lineno = lno }()
64 return s.staticassign(n.Left, n.Right)
65 }
66
67
68
69 func (s *InitSchedule) staticcopy(l *Node, r *Node) bool {
70 if r.Op != ONAME {
71 return false
72 }
73 if r.Class() == PFUNC {
74 gdata(l, r, Widthptr)
75 return true
76 }
77 if r.Class() != PEXTERN || r.Sym.Pkg != localpkg {
78 return false
79 }
80 if r.Name.Defn == nil {
81 return false
82 }
83 if r.Name.Defn.Op != OAS {
84 return false
85 }
86 orig := r
87 r = r.Name.Defn.Right
88
89 for r.Op == OCONVNOP && !types.Identical(r.Type, l.Type) {
90 r = r.Left
91 }
92
93 switch r.Op {
94 case ONAME:
95 if s.staticcopy(l, r) {
96 return true
97 }
98
99
100 s.append(nod(OAS, l, conv(r, l.Type)))
101 return true
102
103 case OLITERAL:
104 if isZero(r) {
105 return true
106 }
107 gdata(l, r, int(l.Type.Width))
108 return true
109
110 case OADDR:
111 switch r.Left.Op {
112 case ONAME:
113 gdata(l, r, int(l.Type.Width))
114 return true
115 }
116
117 case OPTRLIT:
118 switch r.Left.Op {
119 case OARRAYLIT, OSLICELIT, OSTRUCTLIT, OMAPLIT:
120
121 gdata(l, nod(OADDR, s.inittemps[r], nil), int(l.Type.Width))
122 return true
123 }
124
125 case OSLICELIT:
126
127 a := s.inittemps[r]
128
129 n := l.copy()
130 n.Xoffset = l.Xoffset + int64(array_array)
131 gdata(n, nod(OADDR, a, nil), Widthptr)
132 n.Xoffset = l.Xoffset + int64(array_nel)
133 gdata(n, r.Right, Widthptr)
134 n.Xoffset = l.Xoffset + int64(array_cap)
135 gdata(n, r.Right, Widthptr)
136 return true
137
138 case OARRAYLIT, OSTRUCTLIT:
139 p := s.initplans[r]
140
141 n := l.copy()
142 for i := range p.E {
143 e := &p.E[i]
144 n.Xoffset = l.Xoffset + e.Xoffset
145 n.Type = e.Expr.Type
146 if e.Expr.Op == OLITERAL {
147 gdata(n, e.Expr, int(n.Type.Width))
148 continue
149 }
150 ll := n.sepcopy()
151 if s.staticcopy(ll, e.Expr) {
152 continue
153 }
154
155
156 rr := orig.sepcopy()
157 rr.Type = ll.Type
158 rr.Xoffset += e.Xoffset
159 setlineno(rr)
160 s.append(nod(OAS, ll, rr))
161 }
162
163 return true
164 }
165
166 return false
167 }
168
169 func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
170 for r.Op == OCONVNOP {
171 r = r.Left
172 }
173
174 switch r.Op {
175 case ONAME:
176 return s.staticcopy(l, r)
177
178 case OLITERAL:
179 if isZero(r) {
180 return true
181 }
182 gdata(l, r, int(l.Type.Width))
183 return true
184
185 case OADDR:
186 var nam Node
187 if stataddr(&nam, r.Left) {
188 n := *r
189 n.Left = &nam
190 gdata(l, &n, int(l.Type.Width))
191 return true
192 }
193 fallthrough
194
195 case OPTRLIT:
196 switch r.Left.Op {
197 case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT:
198
199 a := staticname(r.Left.Type)
200
201 s.inittemps[r] = a
202 gdata(l, nod(OADDR, a, nil), int(l.Type.Width))
203
204
205 if !s.staticassign(a, r.Left) {
206 s.append(nod(OAS, a, r.Left))
207 }
208 return true
209 }
210
211
212 case OSTR2BYTES:
213 if l.Class() == PEXTERN && r.Left.Op == OLITERAL {
214 sval := r.Left.Val().U.(string)
215 slicebytes(l, sval, len(sval))
216 return true
217 }
218
219 case OSLICELIT:
220 s.initplan(r)
221
222 bound := r.Right.Int64()
223 ta := types.NewArray(r.Type.Elem(), bound)
224 a := staticname(ta)
225 s.inittemps[r] = a
226 n := l.copy()
227 n.Xoffset = l.Xoffset + int64(array_array)
228 gdata(n, nod(OADDR, a, nil), Widthptr)
229 n.Xoffset = l.Xoffset + int64(array_nel)
230 gdata(n, r.Right, Widthptr)
231 n.Xoffset = l.Xoffset + int64(array_cap)
232 gdata(n, r.Right, Widthptr)
233
234
235 l = a
236 fallthrough
237
238 case OARRAYLIT, OSTRUCTLIT:
239 s.initplan(r)
240
241 p := s.initplans[r]
242 n := l.copy()
243 for i := range p.E {
244 e := &p.E[i]
245 n.Xoffset = l.Xoffset + e.Xoffset
246 n.Type = e.Expr.Type
247 if e.Expr.Op == OLITERAL {
248 gdata(n, e.Expr, int(n.Type.Width))
249 continue
250 }
251 setlineno(e.Expr)
252 a := n.sepcopy()
253 if !s.staticassign(a, e.Expr) {
254 s.append(nod(OAS, a, e.Expr))
255 }
256 }
257
258 return true
259
260 case OMAPLIT:
261 break
262
263 case OCLOSURE:
264 if hasemptycvars(r) {
265 if Debug_closure > 0 {
266 Warnl(r.Pos, "closure converted to global")
267 }
268
269
270 gdata(l, r.Func.Closure.Func.Nname, Widthptr)
271 return true
272 }
273 closuredebugruntimecheck(r)
274
275 case OCONVIFACE:
276
277
278
279
280 val := r
281 for val.Op == OCONVIFACE {
282 val = val.Left
283 }
284 if val.Type.IsInterface() {
285
286
287
288
289
290 return Isconst(val, CTNIL)
291 }
292
293 var itab *Node
294 if l.Type.IsEmptyInterface() {
295 itab = typename(val.Type)
296 } else {
297 itab = itabname(val.Type, l.Type)
298 }
299
300
301 n := l.copy()
302
303
304 gdata(n, itab, Widthptr)
305 n.Xoffset += int64(Widthptr)
306
307
308 if isdirectiface(val.Type) {
309 if Isconst(val, CTNIL) {
310
311 return true
312 }
313
314 n.Type = val.Type
315 setlineno(val)
316 a := n.sepcopy()
317 if !s.staticassign(a, val) {
318 s.append(nod(OAS, a, val))
319 }
320 } else {
321
322 a := staticname(val.Type)
323 s.inittemps[val] = a
324 if !s.staticassign(a, val) {
325 s.append(nod(OAS, a, val))
326 }
327 ptr := nod(OADDR, a, nil)
328 n.Type = types.NewPtr(val.Type)
329 gdata(n, ptr, Widthptr)
330 }
331
332 return true
333 }
334
335
336 return false
337 }
338
339
340
341
342
343
344
345
346
347
348
349 type initContext uint8
350
351 const (
352 inInitFunction initContext = iota
353 inNonInitFunction
354 )
355
356 func (c initContext) String() string {
357 if c == inInitFunction {
358 return "inInitFunction"
359 }
360 return "inNonInitFunction"
361 }
362
363
364
365
366
367
368
369 var statuniqgen int
370
371
372
373
374 func staticname(t *types.Type) *Node {
375
376 n := newname(lookup(fmt.Sprintf(".stmp_%d", statuniqgen)))
377 statuniqgen++
378 addvar(n, t, PEXTERN)
379 return n
380 }
381
382 func isLiteral(n *Node) bool {
383
384 return n.Op == OLITERAL && n.Val().Ctype() != CTNIL
385 }
386
387 func (n *Node) isSimpleName() bool {
388 return n.Op == ONAME && n.Addable() && n.Class() != PAUTOHEAP && n.Class() != PEXTERN
389 }
390
391 func litas(l *Node, r *Node, init *Nodes) {
392 a := nod(OAS, l, r)
393 a = typecheck(a, ctxStmt)
394 a = walkexpr(a, init)
395 init.Append(a)
396 }
397
398
399 type initGenType uint8
400
401 const (
402 initDynamic initGenType = 1 << iota
403 initConst
404 )
405
406
407
408 func getdyn(n *Node, top bool) initGenType {
409 switch n.Op {
410 default:
411 if isLiteral(n) {
412 return initConst
413 }
414 return initDynamic
415
416 case OSLICELIT:
417 if !top {
418 return initDynamic
419 }
420 if n.Right.Int64()/4 > int64(n.List.Len()) {
421
422
423
424
425
426
427 return initDynamic
428 }
429
430 case OARRAYLIT, OSTRUCTLIT:
431 }
432
433 var mode initGenType
434 for _, n1 := range n.List.Slice() {
435 switch n1.Op {
436 case OKEY:
437 n1 = n1.Right
438 case OSTRUCTKEY:
439 n1 = n1.Left
440 }
441 mode |= getdyn(n1, false)
442 if mode == initDynamic|initConst {
443 break
444 }
445 }
446 return mode
447 }
448
449
450 func isStaticCompositeLiteral(n *Node) bool {
451 switch n.Op {
452 case OSLICELIT:
453 return false
454 case OARRAYLIT:
455 for _, r := range n.List.Slice() {
456 if r.Op == OKEY {
457 r = r.Right
458 }
459 if !isStaticCompositeLiteral(r) {
460 return false
461 }
462 }
463 return true
464 case OSTRUCTLIT:
465 for _, r := range n.List.Slice() {
466 if r.Op != OSTRUCTKEY {
467 Fatalf("isStaticCompositeLiteral: rhs not OSTRUCTKEY: %v", r)
468 }
469 if !isStaticCompositeLiteral(r.Left) {
470 return false
471 }
472 }
473 return true
474 case OLITERAL:
475 return true
476 case OCONVIFACE:
477
478 val := n
479 for val.Op == OCONVIFACE {
480 val = val.Left
481 }
482 if val.Type.IsInterface() {
483 return Isconst(val, CTNIL)
484 }
485 if isdirectiface(val.Type) && Isconst(val, CTNIL) {
486 return true
487 }
488 return isStaticCompositeLiteral(val)
489 }
490 return false
491 }
492
493
494
495
496
497
498
499
500
501
502 type initKind uint8
503
504 const (
505 initKindStatic initKind = iota + 1
506 initKindDynamic
507 initKindLocalCode
508 )
509
510
511
512 func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes) {
513 var splitnode func(*Node) (a *Node, value *Node)
514 switch n.Op {
515 case OARRAYLIT, OSLICELIT:
516 var k int64
517 splitnode = func(r *Node) (*Node, *Node) {
518 if r.Op == OKEY {
519 k = indexconst(r.Left)
520 if k < 0 {
521 Fatalf("fixedlit: invalid index %v", r.Left)
522 }
523 r = r.Right
524 }
525 a := nod(OINDEX, var_, nodintconst(k))
526 k++
527 return a, r
528 }
529 case OSTRUCTLIT:
530 splitnode = func(r *Node) (*Node, *Node) {
531 if r.Op != OSTRUCTKEY {
532 Fatalf("fixedlit: rhs not OSTRUCTKEY: %v", r)
533 }
534 if r.Sym.IsBlank() {
535 return nblank, r.Left
536 }
537 setlineno(r)
538 return nodSym(ODOT, var_, r.Sym), r.Left
539 }
540 default:
541 Fatalf("fixedlit bad op: %v", n.Op)
542 }
543
544 for _, r := range n.List.Slice() {
545 a, value := splitnode(r)
546
547 switch value.Op {
548 case OSLICELIT:
549 if (kind == initKindStatic && ctxt == inNonInitFunction) || (kind == initKindDynamic && ctxt == inInitFunction) {
550 slicelit(ctxt, value, a, init)
551 continue
552 }
553
554 case OARRAYLIT, OSTRUCTLIT:
555 fixedlit(ctxt, kind, value, a, init)
556 continue
557 }
558
559 islit := isLiteral(value)
560 if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
561 continue
562 }
563
564
565 setlineno(a)
566 a = nod(OAS, a, value)
567 a = typecheck(a, ctxStmt)
568 switch kind {
569 case initKindStatic:
570 genAsStatic(a)
571 case initKindDynamic, initKindLocalCode:
572 a = orderStmtInPlace(a, map[string][]*Node{})
573 a = walkstmt(a)
574 init.Append(a)
575 default:
576 Fatalf("fixedlit: bad kind %d", kind)
577 }
578
579 }
580 }
581
582 func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
583
584 t := types.NewArray(n.Type.Elem(), n.Right.Int64())
585 dowidth(t)
586
587 if ctxt == inNonInitFunction {
588
589 vstat := staticname(t)
590
591 fixedlit(ctxt, initKindStatic, n, vstat, init)
592 fixedlit(ctxt, initKindDynamic, n, vstat, init)
593
594
595 var_ = typecheck(var_, ctxExpr|ctxAssign)
596 var nam Node
597 if !stataddr(&nam, var_) || nam.Class() != PEXTERN {
598 Fatalf("slicelit: %v", var_)
599 }
600
601 var v Node
602 v.Type = types.Types[TINT]
603 setintconst(&v, t.NumElem())
604
605 nam.Xoffset += int64(array_array)
606 gdata(&nam, nod(OADDR, vstat, nil), Widthptr)
607 nam.Xoffset += int64(array_nel) - int64(array_array)
608 gdata(&nam, &v, Widthptr)
609 nam.Xoffset += int64(array_cap) - int64(array_nel)
610 gdata(&nam, &v, Widthptr)
611
612 return
613 }
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636 var vstat *Node
637
638 mode := getdyn(n, true)
639 if mode&initConst != 0 {
640 vstat = staticname(t)
641 if ctxt == inInitFunction {
642 vstat.Name.SetReadonly(true)
643 }
644 fixedlit(ctxt, initKindStatic, n, vstat, init)
645 }
646
647
648 vauto := temp(types.NewPtr(t))
649
650
651 var a *Node
652 if x := prealloc[n]; x != nil {
653
654 if !types.Identical(t, x.Type) {
655 panic("dotdotdot base type does not match order's assigned type")
656 }
657
658 if vstat == nil {
659 a = nod(OAS, x, nil)
660 a = typecheck(a, ctxStmt)
661 init.Append(a)
662 } else {
663
664
665 init.Append(nod(OVARDEF, x, nil))
666 }
667
668 a = nod(OADDR, x, nil)
669 } else if n.Esc == EscNone {
670 a = temp(t)
671 if vstat == nil {
672 a = nod(OAS, temp(t), nil)
673 a = typecheck(a, ctxStmt)
674 init.Append(a)
675 a = a.Left
676 } else {
677 init.Append(nod(OVARDEF, a, nil))
678 }
679
680 a = nod(OADDR, a, nil)
681 } else {
682 a = nod(ONEW, nil, nil)
683 a.List.Set1(typenod(t))
684 }
685
686 a = nod(OAS, vauto, a)
687 a = typecheck(a, ctxStmt)
688 a = walkexpr(a, init)
689 init.Append(a)
690
691 if vstat != nil {
692
693 a = nod(ODEREF, vauto, nil)
694
695 a = nod(OAS, a, vstat)
696 a = typecheck(a, ctxStmt)
697 a = walkexpr(a, init)
698 init.Append(a)
699 }
700
701
702 var index int64
703 for _, value := range n.List.Slice() {
704 if value.Op == OKEY {
705 index = indexconst(value.Left)
706 if index < 0 {
707 Fatalf("slicelit: invalid index %v", value.Left)
708 }
709 value = value.Right
710 }
711 a := nod(OINDEX, vauto, nodintconst(index))
712 a.SetBounded(true)
713 index++
714
715
716
717 switch value.Op {
718 case OSLICELIT:
719 break
720
721 case OARRAYLIT, OSTRUCTLIT:
722 k := initKindDynamic
723 if vstat == nil {
724
725
726 k = initKindLocalCode
727 }
728 fixedlit(ctxt, k, value, a, init)
729 continue
730 }
731
732 if vstat != nil && isLiteral(value) {
733 continue
734 }
735
736
737 setlineno(value)
738 a = nod(OAS, a, value)
739
740 a = typecheck(a, ctxStmt)
741 a = orderStmtInPlace(a, map[string][]*Node{})
742 a = walkstmt(a)
743 init.Append(a)
744 }
745
746
747 a = nod(OAS, var_, nod(OSLICE, vauto, nil))
748
749 a = typecheck(a, ctxStmt)
750 a = orderStmtInPlace(a, map[string][]*Node{})
751 a = walkstmt(a)
752 init.Append(a)
753 }
754
755 func maplit(n *Node, m *Node, init *Nodes) {
756
757 a := nod(OMAKE, nil, nil)
758 a.Esc = n.Esc
759 a.List.Set2(typenod(n.Type), nodintconst(int64(n.List.Len())))
760 litas(m, a, init)
761
762 entries := n.List.Slice()
763
764
765
766 for _, r := range entries {
767 if !isStaticCompositeLiteral(r.Left) || !isStaticCompositeLiteral(r.Right) {
768 Fatalf("maplit: entry is not a literal: %v", r)
769 }
770 }
771
772 if len(entries) > 25 {
773
774
775
776 tk := types.NewArray(n.Type.Key(), int64(len(entries)))
777 te := types.NewArray(n.Type.Elem(), int64(len(entries)))
778
779
780 dowidth(tk)
781 dowidth(te)
782
783
784 vstatk := staticname(tk)
785 vstatk.Name.SetReadonly(true)
786 vstate := staticname(te)
787 vstate.Name.SetReadonly(true)
788
789 datak := nod(OARRAYLIT, nil, nil)
790 datae := nod(OARRAYLIT, nil, nil)
791 for _, r := range entries {
792 datak.List.Append(r.Left)
793 datae.List.Append(r.Right)
794 }
795 fixedlit(inInitFunction, initKindStatic, datak, vstatk, init)
796 fixedlit(inInitFunction, initKindStatic, datae, vstate, init)
797
798
799
800
801
802 i := temp(types.Types[TINT])
803 rhs := nod(OINDEX, vstate, i)
804 rhs.SetBounded(true)
805
806 kidx := nod(OINDEX, vstatk, i)
807 kidx.SetBounded(true)
808 lhs := nod(OINDEX, m, kidx)
809
810 zero := nod(OAS, i, nodintconst(0))
811 cond := nod(OLT, i, nodintconst(tk.NumElem()))
812 incr := nod(OAS, i, nod(OADD, i, nodintconst(1)))
813 body := nod(OAS, lhs, rhs)
814
815 loop := nod(OFOR, cond, incr)
816 loop.Nbody.Set1(body)
817 loop.Ninit.Set1(zero)
818
819 loop = typecheck(loop, ctxStmt)
820 loop = walkstmt(loop)
821 init.Append(loop)
822 return
823 }
824
825
826
827
828
829 tmpkey := temp(m.Type.Key())
830 tmpelem := temp(m.Type.Elem())
831
832 for _, r := range entries {
833 index, elem := r.Left, r.Right
834
835 setlineno(index)
836 a := nod(OAS, tmpkey, index)
837 a = typecheck(a, ctxStmt)
838 a = walkstmt(a)
839 init.Append(a)
840
841 setlineno(elem)
842 a = nod(OAS, tmpelem, elem)
843 a = typecheck(a, ctxStmt)
844 a = walkstmt(a)
845 init.Append(a)
846
847 setlineno(tmpelem)
848 a = nod(OAS, nod(OINDEX, m, tmpkey), tmpelem)
849 a = typecheck(a, ctxStmt)
850 a = walkstmt(a)
851 init.Append(a)
852 }
853
854 a = nod(OVARKILL, tmpkey, nil)
855 a = typecheck(a, ctxStmt)
856 init.Append(a)
857 a = nod(OVARKILL, tmpelem, nil)
858 a = typecheck(a, ctxStmt)
859 init.Append(a)
860 }
861
862 func anylit(n *Node, var_ *Node, init *Nodes) {
863 t := n.Type
864 switch n.Op {
865 default:
866 Fatalf("anylit: not lit, op=%v node=%v", n.Op, n)
867
868 case ONAME:
869 a := nod(OAS, var_, n)
870 a = typecheck(a, ctxStmt)
871 init.Append(a)
872
873 case OPTRLIT:
874 if !t.IsPtr() {
875 Fatalf("anylit: not ptr")
876 }
877
878 var r *Node
879 if n.Right != nil {
880
881 init.Append(nod(OAS, n.Right, nil))
882 r = nod(OADDR, n.Right, nil)
883 r = typecheck(r, ctxExpr)
884 } else {
885 r = nod(ONEW, nil, nil)
886 r.SetTypecheck(1)
887 r.Type = t
888 r.Esc = n.Esc
889 }
890
891 r = walkexpr(r, init)
892 a := nod(OAS, var_, r)
893
894 a = typecheck(a, ctxStmt)
895 init.Append(a)
896
897 var_ = nod(ODEREF, var_, nil)
898 var_ = typecheck(var_, ctxExpr|ctxAssign)
899 anylit(n.Left, var_, init)
900
901 case OSTRUCTLIT, OARRAYLIT:
902 if !t.IsStruct() && !t.IsArray() {
903 Fatalf("anylit: not struct/array")
904 }
905
906 if var_.isSimpleName() && n.List.Len() > 4 {
907
908 vstat := staticname(t)
909 vstat.Name.SetReadonly(true)
910
911 ctxt := inInitFunction
912 if n.Op == OARRAYLIT {
913 ctxt = inNonInitFunction
914 }
915 fixedlit(ctxt, initKindStatic, n, vstat, init)
916
917
918 a := nod(OAS, var_, vstat)
919
920 a = typecheck(a, ctxStmt)
921 a = walkexpr(a, init)
922 init.Append(a)
923
924
925 fixedlit(inInitFunction, initKindDynamic, n, var_, init)
926 break
927 }
928
929 var components int64
930 if n.Op == OARRAYLIT {
931 components = t.NumElem()
932 } else {
933 components = int64(t.NumFields())
934 }
935
936 if var_.isSimpleName() || int64(n.List.Len()) < components {
937 a := nod(OAS, var_, nil)
938 a = typecheck(a, ctxStmt)
939 a = walkexpr(a, init)
940 init.Append(a)
941 }
942
943 fixedlit(inInitFunction, initKindLocalCode, n, var_, init)
944
945 case OSLICELIT:
946 slicelit(inInitFunction, n, var_, init)
947
948 case OMAPLIT:
949 if !t.IsMap() {
950 Fatalf("anylit: not map")
951 }
952 maplit(n, var_, init)
953 }
954 }
955
956 func oaslit(n *Node, init *Nodes) bool {
957 if n.Left == nil || n.Right == nil {
958
959 return false
960 }
961 if n.Left.Type == nil || n.Right.Type == nil {
962
963 return false
964 }
965 if !n.Left.isSimpleName() {
966
967 return false
968 }
969 if !types.Identical(n.Left.Type, n.Right.Type) {
970
971 return false
972 }
973
974 switch n.Right.Op {
975 default:
976
977 return false
978
979 case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
980 if vmatch1(n.Left, n.Right) {
981
982 return false
983 }
984 anylit(n.Right, n.Left, init)
985 }
986
987 n.Op = OEMPTY
988 n.Right = nil
989 return true
990 }
991
992 func getlit(lit *Node) int {
993 if smallintconst(lit) {
994 return int(lit.Int64())
995 }
996 return -1
997 }
998
999
1000 func stataddr(nam *Node, n *Node) bool {
1001 if n == nil {
1002 return false
1003 }
1004
1005 switch n.Op {
1006 case ONAME:
1007 *nam = *n
1008 return n.Addable()
1009
1010 case ODOT:
1011 if !stataddr(nam, n.Left) {
1012 break
1013 }
1014 nam.Xoffset += n.Xoffset
1015 nam.Type = n.Type
1016 return true
1017
1018 case OINDEX:
1019 if n.Left.Type.IsSlice() {
1020 break
1021 }
1022 if !stataddr(nam, n.Left) {
1023 break
1024 }
1025 l := getlit(n.Right)
1026 if l < 0 {
1027 break
1028 }
1029
1030
1031 if n.Type.Width != 0 && thearch.MAXWIDTH/n.Type.Width <= int64(l) {
1032 break
1033 }
1034 nam.Xoffset += int64(l) * n.Type.Width
1035 nam.Type = n.Type
1036 return true
1037 }
1038
1039 return false
1040 }
1041
1042 func (s *InitSchedule) initplan(n *Node) {
1043 if s.initplans[n] != nil {
1044 return
1045 }
1046 p := new(InitPlan)
1047 s.initplans[n] = p
1048 switch n.Op {
1049 default:
1050 Fatalf("initplan")
1051
1052 case OARRAYLIT, OSLICELIT:
1053 var k int64
1054 for _, a := range n.List.Slice() {
1055 if a.Op == OKEY {
1056 k = indexconst(a.Left)
1057 if k < 0 {
1058 Fatalf("initplan arraylit: invalid index %v", a.Left)
1059 }
1060 a = a.Right
1061 }
1062 s.addvalue(p, k*n.Type.Elem().Width, a)
1063 k++
1064 }
1065
1066 case OSTRUCTLIT:
1067 for _, a := range n.List.Slice() {
1068 if a.Op != OSTRUCTKEY {
1069 Fatalf("initplan structlit")
1070 }
1071 if a.Sym.IsBlank() {
1072 continue
1073 }
1074 s.addvalue(p, a.Xoffset, a.Left)
1075 }
1076
1077 case OMAPLIT:
1078 for _, a := range n.List.Slice() {
1079 if a.Op != OKEY {
1080 Fatalf("initplan maplit")
1081 }
1082 s.addvalue(p, -1, a.Right)
1083 }
1084 }
1085 }
1086
1087 func (s *InitSchedule) addvalue(p *InitPlan, xoffset int64, n *Node) {
1088
1089 if isZero(n) {
1090 return
1091 }
1092
1093
1094 if isvaluelit(n) {
1095 s.initplan(n)
1096 q := s.initplans[n]
1097 for _, qe := range q.E {
1098
1099 qe.Xoffset += xoffset
1100 p.E = append(p.E, qe)
1101 }
1102 return
1103 }
1104
1105
1106 p.E = append(p.E, InitEntry{Xoffset: xoffset, Expr: n})
1107 }
1108
1109 func isZero(n *Node) bool {
1110 switch n.Op {
1111 case OLITERAL:
1112 switch u := n.Val().U.(type) {
1113 default:
1114 Dump("unexpected literal", n)
1115 Fatalf("isZero")
1116 case *NilVal:
1117 return true
1118 case string:
1119 return u == ""
1120 case bool:
1121 return !u
1122 case *Mpint:
1123 return u.CmpInt64(0) == 0
1124 case *Mpflt:
1125 return u.CmpFloat64(0) == 0
1126 case *Mpcplx:
1127 return u.Real.CmpFloat64(0) == 0 && u.Imag.CmpFloat64(0) == 0
1128 }
1129
1130 case OARRAYLIT:
1131 for _, n1 := range n.List.Slice() {
1132 if n1.Op == OKEY {
1133 n1 = n1.Right
1134 }
1135 if !isZero(n1) {
1136 return false
1137 }
1138 }
1139 return true
1140
1141 case OSTRUCTLIT:
1142 for _, n1 := range n.List.Slice() {
1143 if !isZero(n1.Left) {
1144 return false
1145 }
1146 }
1147 return true
1148 }
1149
1150 return false
1151 }
1152
1153 func isvaluelit(n *Node) bool {
1154 return n.Op == OARRAYLIT || n.Op == OSTRUCTLIT
1155 }
1156
1157 func genAsStatic(as *Node) {
1158 if as.Left.Type == nil {
1159 Fatalf("genAsStatic as.Left not typechecked")
1160 }
1161
1162 var nam Node
1163 if !stataddr(&nam, as.Left) || (nam.Class() != PEXTERN && as.Left != nblank) {
1164 Fatalf("genAsStatic: lhs %v", as.Left)
1165 }
1166
1167 switch {
1168 case as.Right.Op == OLITERAL:
1169 case as.Right.Op == ONAME && as.Right.Class() == PFUNC:
1170 default:
1171 Fatalf("genAsStatic: rhs %v", as.Right)
1172 }
1173
1174 gdata(&nam, as.Right, int(as.Right.Type.Width))
1175 }
1176
View as plain text