]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/gc/sinit.go
[dev.ssa] Merge remote-tracking branch 'origin/master' into ssamerge
[gostls13.git] / src / cmd / compile / internal / gc / sinit.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package gc
6
7 import (
8         "cmd/internal/obj"
9         "fmt"
10 )
11
12 // static initialization
13 const (
14         InitNotStarted = 0
15         InitDone       = 1
16         InitPending    = 2
17 )
18
19 var (
20         initlist  []*Node
21         initplans map[*Node]*InitPlan
22         inittemps = make(map[*Node]*Node)
23 )
24
25 // init1 walks the AST starting at n, and accumulates in out
26 // the list of definitions needing init code in dependency order.
27 func init1(n *Node, out **NodeList) {
28         if n == nil {
29                 return
30         }
31         init1(n.Left, out)
32         init1(n.Right, out)
33         for l := n.List; l != nil; l = l.Next {
34                 init1(l.N, out)
35         }
36
37         if n.Left != nil && n.Type != nil && n.Left.Op == OTYPE && n.Class == PFUNC {
38                 // Methods called as Type.Method(receiver, ...).
39                 // Definitions for method expressions are stored in type->nname.
40                 init1(n.Type.Nname, out)
41         }
42
43         if n.Op != ONAME {
44                 return
45         }
46         switch n.Class {
47         case PEXTERN, PFUNC:
48         default:
49                 if isblank(n) && n.Name.Curfn == nil && n.Name.Defn != nil && n.Name.Defn.Initorder == InitNotStarted {
50                         // blank names initialization is part of init() but not
51                         // when they are inside a function.
52                         break
53                 }
54                 return
55         }
56
57         if n.Initorder == InitDone {
58                 return
59         }
60         if n.Initorder == InitPending {
61                 // Since mutually recursive sets of functions are allowed,
62                 // we don't necessarily raise an error if n depends on a node
63                 // which is already waiting for its dependencies to be visited.
64                 //
65                 // initlist contains a cycle of identifiers referring to each other.
66                 // If this cycle contains a variable, then this variable refers to itself.
67                 // Conversely, if there exists an initialization cycle involving
68                 // a variable in the program, the tree walk will reach a cycle
69                 // involving that variable.
70                 if n.Class != PFUNC {
71                         foundinitloop(n, n)
72                 }
73
74                 for i := len(initlist) - 1; i >= 0; i-- {
75                         x := initlist[i]
76                         if x == n {
77                                 break
78                         }
79                         if x.Class != PFUNC {
80                                 foundinitloop(n, x)
81                         }
82                 }
83
84                 // The loop involves only functions, ok.
85                 return
86         }
87
88         // reached a new unvisited node.
89         n.Initorder = InitPending
90         initlist = append(initlist, n)
91
92         // make sure that everything n depends on is initialized.
93         // n->defn is an assignment to n
94         if defn := n.Name.Defn; defn != nil {
95                 switch defn.Op {
96                 default:
97                         Dump("defn", defn)
98                         Fatalf("init1: bad defn")
99
100                 case ODCLFUNC:
101                         init2list(defn.Nbody, out)
102
103                 case OAS:
104                         if defn.Left != n {
105                                 Dump("defn", defn)
106                                 Fatalf("init1: bad defn")
107                         }
108                         if isblank(defn.Left) && candiscard(defn.Right) {
109                                 defn.Op = OEMPTY
110                                 defn.Left = nil
111                                 defn.Right = nil
112                                 break
113                         }
114
115                         init2(defn.Right, out)
116                         if Debug['j'] != 0 {
117                                 fmt.Printf("%v\n", n.Sym)
118                         }
119                         if isblank(n) || !staticinit(n, out) {
120                                 if Debug['%'] != 0 {
121                                         Dump("nonstatic", defn)
122                                 }
123                                 *out = list(*out, defn)
124                         }
125
126                 case OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV:
127                         if defn.Initorder == InitDone {
128                                 break
129                         }
130                         defn.Initorder = InitPending
131                         for l := defn.Rlist; l != nil; l = l.Next {
132                                 init1(l.N, out)
133                         }
134                         if Debug['%'] != 0 {
135                                 Dump("nonstatic", defn)
136                         }
137                         *out = list(*out, defn)
138                         defn.Initorder = InitDone
139                 }
140         }
141
142         last := len(initlist) - 1
143         if initlist[last] != n {
144                 Fatalf("bad initlist %v", initlist)
145         }
146         initlist[last] = nil // allow GC
147         initlist = initlist[:last]
148
149         n.Initorder = InitDone
150         return
151 }
152
153 // foundinitloop prints an init loop error and exits.
154 func foundinitloop(node, visited *Node) {
155         // If there have already been errors printed,
156         // those errors probably confused us and
157         // there might not be a loop. Let the user
158         // fix those first.
159         Flusherrors()
160         if nerrors > 0 {
161                 errorexit()
162         }
163
164         // Find the index of node and visited in the initlist.
165         var nodeindex, visitedindex int
166         for ; initlist[nodeindex] != node; nodeindex++ {
167         }
168         for ; initlist[visitedindex] != visited; visitedindex++ {
169         }
170
171         // There is a loop involving visited. We know about node and
172         // initlist = n1 <- ... <- visited <- ... <- node <- ...
173         fmt.Printf("%v: initialization loop:\n", visited.Line())
174
175         // Print visited -> ... -> n1 -> node.
176         for _, n := range initlist[visitedindex:] {
177                 fmt.Printf("\t%v %v refers to\n", n.Line(), n.Sym)
178         }
179
180         // Print node -> ... -> visited.
181         for _, n := range initlist[nodeindex:visitedindex] {
182                 fmt.Printf("\t%v %v refers to\n", n.Line(), n.Sym)
183         }
184
185         fmt.Printf("\t%v %v\n", visited.Line(), visited.Sym)
186         errorexit()
187 }
188
189 // recurse over n, doing init1 everywhere.
190 func init2(n *Node, out **NodeList) {
191         if n == nil || n.Initorder == InitDone {
192                 return
193         }
194
195         if n.Op == ONAME && n.Ninit != nil {
196                 Fatalf("name %v with ninit: %v\n", n.Sym, Nconv(n, obj.FmtSign))
197         }
198
199         init1(n, out)
200         init2(n.Left, out)
201         init2(n.Right, out)
202         init2list(n.Ninit, out)
203         init2list(n.List, out)
204         init2list(n.Rlist, out)
205         init2list(n.Nbody, out)
206
207         if n.Op == OCLOSURE {
208                 init2list(n.Func.Closure.Nbody, out)
209         }
210         if n.Op == ODOTMETH || n.Op == OCALLPART {
211                 init2(n.Type.Nname, out)
212         }
213 }
214
215 func init2list(l *NodeList, out **NodeList) {
216         for ; l != nil; l = l.Next {
217                 init2(l.N, out)
218         }
219 }
220
221 func initreorder(l *NodeList, out **NodeList) {
222         var n *Node
223
224         for ; l != nil; l = l.Next {
225                 n = l.N
226                 switch n.Op {
227                 case ODCLFUNC, ODCLCONST, ODCLTYPE:
228                         continue
229                 }
230
231                 initreorder(n.Ninit, out)
232                 n.Ninit = nil
233                 init1(n, out)
234         }
235 }
236
237 // initfix computes initialization order for a list l of top-level
238 // declarations and outputs the corresponding list of statements
239 // to include in the init() function body.
240 func initfix(l *NodeList) *NodeList {
241         var lout *NodeList
242         initplans = make(map[*Node]*InitPlan)
243         lno := int(lineno)
244         initreorder(l, &lout)
245         lineno = int32(lno)
246         initplans = nil
247         return lout
248 }
249
250 // compilation of top-level (static) assignments
251 // into DATA statements if at all possible.
252 func staticinit(n *Node, out **NodeList) bool {
253         if n.Op != ONAME || n.Class != PEXTERN || n.Name.Defn == nil || n.Name.Defn.Op != OAS {
254                 Fatalf("staticinit")
255         }
256
257         lineno = n.Lineno
258         l := n.Name.Defn.Left
259         r := n.Name.Defn.Right
260         return staticassign(l, r, out)
261 }
262
263 // like staticassign but we are copying an already
264 // initialized value r.
265 func staticcopy(l *Node, r *Node, out **NodeList) bool {
266         if r.Op != ONAME {
267                 return false
268         }
269         if r.Class == PFUNC {
270                 gdata(l, r, Widthptr)
271                 return true
272         }
273         if r.Class != PEXTERN || r.Sym.Pkg != localpkg {
274                 return false
275         }
276         if r.Name.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
277                 return false
278         }
279         if r.Name.Defn.Op != OAS {
280                 return false
281         }
282         orig := r
283         r = r.Name.Defn.Right
284
285         for r.Op == OCONVNOP {
286                 r = r.Left
287         }
288
289         switch r.Op {
290         case ONAME:
291                 if staticcopy(l, r, out) {
292                         return true
293                 }
294                 *out = list(*out, Nod(OAS, l, r))
295                 return true
296
297         case OLITERAL:
298                 if iszero(r) {
299                         return true
300                 }
301                 gdata(l, r, int(l.Type.Width))
302                 return true
303
304         case OADDR:
305                 switch r.Left.Op {
306                 case ONAME:
307                         gdata(l, r, int(l.Type.Width))
308                         return true
309                 }
310
311         case OPTRLIT:
312                 switch r.Left.Op {
313                 //dump("not static addr", r);
314                 default:
315                         break
316
317                         // copy pointer
318                 case OARRAYLIT, OSTRUCTLIT, OMAPLIT:
319                         gdata(l, Nod(OADDR, inittemps[r], nil), int(l.Type.Width))
320
321                         return true
322                 }
323
324         case OARRAYLIT:
325                 if Isslice(r.Type) {
326                         // copy slice
327                         a := inittemps[r]
328
329                         n := *l
330                         n.Xoffset = l.Xoffset + int64(Array_array)
331                         gdata(&n, Nod(OADDR, a, nil), Widthptr)
332                         n.Xoffset = l.Xoffset + int64(Array_nel)
333                         gdata(&n, r.Right, Widthint)
334                         n.Xoffset = l.Xoffset + int64(Array_cap)
335                         gdata(&n, r.Right, Widthint)
336                         return true
337                 }
338                 fallthrough
339
340                 // fall through
341         case OSTRUCTLIT:
342                 p := initplans[r]
343
344                 n := *l
345                 for i := range p.E {
346                         e := &p.E[i]
347                         n.Xoffset = l.Xoffset + e.Xoffset
348                         n.Type = e.Expr.Type
349                         if e.Expr.Op == OLITERAL {
350                                 gdata(&n, e.Expr, int(n.Type.Width))
351                         } else {
352                                 ll := Nod(OXXX, nil, nil)
353                                 *ll = n
354                                 ll.Orig = ll // completely separate copy
355                                 if !staticassign(ll, e.Expr, out) {
356                                         // Requires computation, but we're
357                                         // copying someone else's computation.
358                                         rr := Nod(OXXX, nil, nil)
359
360                                         *rr = *orig
361                                         rr.Orig = rr // completely separate copy
362                                         rr.Type = ll.Type
363                                         rr.Xoffset += e.Xoffset
364                                         setlineno(rr)
365                                         *out = list(*out, Nod(OAS, ll, rr))
366                                 }
367                         }
368                 }
369
370                 return true
371         }
372
373         return false
374 }
375
376 func staticassign(l *Node, r *Node, out **NodeList) bool {
377         for r.Op == OCONVNOP {
378                 r = r.Left
379         }
380
381         switch r.Op {
382         case ONAME:
383                 return staticcopy(l, r, out)
384
385         case OLITERAL:
386                 if iszero(r) {
387                         return true
388                 }
389                 gdata(l, r, int(l.Type.Width))
390                 return true
391
392         case OADDR:
393                 var nam Node
394                 if stataddr(&nam, r.Left) {
395                         n := *r
396                         n.Left = &nam
397                         gdata(l, &n, int(l.Type.Width))
398                         return true
399                 }
400                 fallthrough
401
402         case OPTRLIT:
403                 switch r.Left.Op {
404                 case OARRAYLIT, OMAPLIT, OSTRUCTLIT:
405                         // Init pointer.
406                         a := staticname(r.Left.Type, 1)
407
408                         inittemps[r] = a
409                         gdata(l, Nod(OADDR, a, nil), int(l.Type.Width))
410
411                         // Init underlying literal.
412                         if !staticassign(a, r.Left, out) {
413                                 *out = list(*out, Nod(OAS, a, r.Left))
414                         }
415                         return true
416                 }
417                 //dump("not static ptrlit", r);
418
419         case OSTRARRAYBYTE:
420                 if l.Class == PEXTERN && r.Left.Op == OLITERAL {
421                         sval := r.Left.Val().U.(string)
422                         slicebytes(l, sval, len(sval))
423                         return true
424                 }
425
426         case OARRAYLIT:
427                 initplan(r)
428                 if Isslice(r.Type) {
429                         // Init slice.
430                         ta := typ(TARRAY)
431
432                         ta.Type = r.Type.Type
433                         ta.Bound = Mpgetfix(r.Right.Val().U.(*Mpint))
434                         a := staticname(ta, 1)
435                         inittemps[r] = a
436                         n := *l
437                         n.Xoffset = l.Xoffset + int64(Array_array)
438                         gdata(&n, Nod(OADDR, a, nil), Widthptr)
439                         n.Xoffset = l.Xoffset + int64(Array_nel)
440                         gdata(&n, r.Right, Widthint)
441                         n.Xoffset = l.Xoffset + int64(Array_cap)
442                         gdata(&n, r.Right, Widthint)
443
444                         // Fall through to init underlying array.
445                         l = a
446                 }
447                 fallthrough
448
449         case OSTRUCTLIT:
450                 initplan(r)
451
452                 p := initplans[r]
453                 n := *l
454                 for i := range p.E {
455                         e := &p.E[i]
456                         n.Xoffset = l.Xoffset + e.Xoffset
457                         n.Type = e.Expr.Type
458                         if e.Expr.Op == OLITERAL {
459                                 gdata(&n, e.Expr, int(n.Type.Width))
460                         } else {
461                                 setlineno(e.Expr)
462                                 a := Nod(OXXX, nil, nil)
463                                 *a = n
464                                 a.Orig = a // completely separate copy
465                                 if !staticassign(a, e.Expr, out) {
466                                         *out = list(*out, Nod(OAS, a, e.Expr))
467                                 }
468                         }
469                 }
470
471                 return true
472
473         case OMAPLIT:
474                 // TODO: Table-driven map insert.
475                 break
476
477         case OCLOSURE:
478                 if len(r.Func.Cvars.Slice()) == 0 {
479                         // Closures with no captured variables are globals,
480                         // so the assignment can be done at link time.
481                         n := *l
482                         gdata(&n, r.Func.Closure.Func.Nname, Widthptr)
483                         return true
484                 }
485         }
486
487         //dump("not static", r);
488         return false
489 }
490
491 // from here down is the walk analysis
492 // of composite literals.
493 // most of the work is to generate
494 // data statements for the constant
495 // part of the composite literal.
496 func staticname(t *Type, ctxt int) *Node {
497         n := newname(Lookupf("statictmp_%.4d", statuniqgen))
498         statuniqgen++
499         if ctxt == 0 {
500                 n.Name.Readonly = true
501         }
502         addvar(n, t, PEXTERN)
503         return n
504 }
505
506 func isliteral(n *Node) bool {
507         if n.Op == OLITERAL {
508                 if n.Val().Ctype() != CTNIL {
509                         return true
510                 }
511         }
512         return false
513 }
514
515 func simplename(n *Node) bool {
516         if n.Op != ONAME {
517                 return false
518         }
519         if !n.Addable {
520                 return false
521         }
522         if n.Class&PHEAP != 0 {
523                 return false
524         }
525         if n.Class == PPARAMREF {
526                 return false
527         }
528         return true
529 }
530
531 func litas(l *Node, r *Node, init **NodeList) {
532         a := Nod(OAS, l, r)
533         typecheck(&a, Etop)
534         walkexpr(&a, init)
535         *init = list(*init, a)
536 }
537
538 const (
539         MODEDYNAM = 1
540         MODECONST = 2
541 )
542
543 func getdyn(n *Node, top int) int {
544         mode := 0
545         switch n.Op {
546         default:
547                 if isliteral(n) {
548                         return MODECONST
549                 }
550                 return MODEDYNAM
551
552         case OARRAYLIT:
553                 if top == 0 && n.Type.Bound < 0 {
554                         return MODEDYNAM
555                 }
556                 fallthrough
557
558         case OSTRUCTLIT:
559                 break
560         }
561
562         for nl := n.List; nl != nil; nl = nl.Next {
563                 value := nl.N.Right
564                 mode |= getdyn(value, 0)
565                 if mode == MODEDYNAM|MODECONST {
566                         break
567                 }
568         }
569
570         return mode
571 }
572
573 func structlit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
574         for nl := n.List; nl != nil; nl = nl.Next {
575                 r := nl.N
576                 if r.Op != OKEY {
577                         Fatalf("structlit: rhs not OKEY: %v", r)
578                 }
579                 index := r.Left
580                 value := r.Right
581
582                 var a *Node
583
584                 switch value.Op {
585                 case OARRAYLIT:
586                         if value.Type.Bound < 0 {
587                                 if pass == 1 && ctxt != 0 {
588                                         a = Nod(ODOT, var_, newname(index.Sym))
589                                         slicelit(ctxt, value, a, init)
590                                 } else if pass == 2 && ctxt == 0 {
591                                         a = Nod(ODOT, var_, newname(index.Sym))
592                                         slicelit(ctxt, value, a, init)
593                                 } else if pass == 3 {
594                                         break
595                                 }
596                                 continue
597                         }
598
599                         a = Nod(ODOT, var_, newname(index.Sym))
600                         arraylit(ctxt, pass, value, a, init)
601                         continue
602
603                 case OSTRUCTLIT:
604                         a = Nod(ODOT, var_, newname(index.Sym))
605                         structlit(ctxt, pass, value, a, init)
606                         continue
607                 }
608
609                 if isliteral(value) {
610                         if pass == 2 {
611                                 continue
612                         }
613                 } else if pass == 1 {
614                         continue
615                 }
616
617                 // build list of var.field = expr
618                 setlineno(value)
619                 a = Nod(ODOT, var_, newname(index.Sym))
620
621                 a = Nod(OAS, a, value)
622                 typecheck(&a, Etop)
623                 if pass == 1 {
624                         walkexpr(&a, init) // add any assignments in r to top
625                         if a.Op != OAS {
626                                 Fatalf("structlit: not as")
627                         }
628                         a.Dodata = 2
629                 } else {
630                         orderstmtinplace(&a)
631                         walkstmt(&a)
632                 }
633
634                 *init = list(*init, a)
635         }
636 }
637
638 func arraylit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
639         for l := n.List; l != nil; l = l.Next {
640                 r := l.N
641                 if r.Op != OKEY {
642                         Fatalf("arraylit: rhs not OKEY: %v", r)
643                 }
644                 index := r.Left
645                 value := r.Right
646
647                 var a *Node
648
649                 switch value.Op {
650                 case OARRAYLIT:
651                         if value.Type.Bound < 0 {
652                                 if pass == 1 && ctxt != 0 {
653                                         a = Nod(OINDEX, var_, index)
654                                         slicelit(ctxt, value, a, init)
655                                 } else if pass == 2 && ctxt == 0 {
656                                         a = Nod(OINDEX, var_, index)
657                                         slicelit(ctxt, value, a, init)
658                                 } else if pass == 3 {
659                                         break
660                                 }
661                                 continue
662                         }
663
664                         a = Nod(OINDEX, var_, index)
665                         arraylit(ctxt, pass, value, a, init)
666                         continue
667
668                 case OSTRUCTLIT:
669                         a = Nod(OINDEX, var_, index)
670                         structlit(ctxt, pass, value, a, init)
671                         continue
672                 }
673
674                 if isliteral(index) && isliteral(value) {
675                         if pass == 2 {
676                                 continue
677                         }
678                 } else if pass == 1 {
679                         continue
680                 }
681
682                 // build list of var[index] = value
683                 setlineno(value)
684                 a = Nod(OINDEX, var_, index)
685
686                 a = Nod(OAS, a, value)
687                 typecheck(&a, Etop)
688                 if pass == 1 {
689                         walkexpr(&a, init)
690                         if a.Op != OAS {
691                                 Fatalf("arraylit: not as")
692                         }
693                         a.Dodata = 2
694                 } else {
695                         orderstmtinplace(&a)
696                         walkstmt(&a)
697                 }
698
699                 *init = list(*init, a)
700         }
701 }
702
703 func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) {
704         // make an array type
705         t := shallow(n.Type)
706
707         t.Bound = Mpgetfix(n.Right.Val().U.(*Mpint))
708         t.Width = 0
709         t.Sym = nil
710         t.Haspointers = 0
711         dowidth(t)
712
713         if ctxt != 0 {
714                 // put everything into static array
715                 vstat := staticname(t, ctxt)
716
717                 arraylit(ctxt, 1, n, vstat, init)
718                 arraylit(ctxt, 2, n, vstat, init)
719
720                 // copy static to slice
721                 a := Nod(OSLICE, vstat, Nod(OKEY, nil, nil))
722
723                 a = Nod(OAS, var_, a)
724                 typecheck(&a, Etop)
725                 a.Dodata = 2
726                 *init = list(*init, a)
727                 return
728         }
729
730         // recipe for var = []t{...}
731         // 1. make a static array
732         //      var vstat [...]t
733         // 2. assign (data statements) the constant part
734         //      vstat = constpart{}
735         // 3. make an auto pointer to array and allocate heap to it
736         //      var vauto *[...]t = new([...]t)
737         // 4. copy the static array to the auto array
738         //      *vauto = vstat
739         // 5. assign slice of allocated heap to var
740         //      var = [0:]*auto
741         // 6. for each dynamic part assign to the slice
742         //      var[i] = dynamic part
743         //
744         // an optimization is done if there is no constant part
745         //      3. var vauto *[...]t = new([...]t)
746         //      5. var = [0:]*auto
747         //      6. var[i] = dynamic part
748
749         // if the literal contains constants,
750         // make static initialized array (1),(2)
751         var vstat *Node
752
753         mode := getdyn(n, 1)
754         if mode&MODECONST != 0 {
755                 vstat = staticname(t, ctxt)
756                 arraylit(ctxt, 1, n, vstat, init)
757         }
758
759         // make new auto *array (3 declare)
760         vauto := temp(Ptrto(t))
761
762         // set auto to point at new temp or heap (3 assign)
763         var a *Node
764         if x := prealloc[n]; x != nil {
765                 // temp allocated during order.go for dddarg
766                 x.Type = t
767
768                 if vstat == nil {
769                         a = Nod(OAS, x, nil)
770                         typecheck(&a, Etop)
771                         *init = list(*init, a) // zero new temp
772                 }
773
774                 a = Nod(OADDR, x, nil)
775         } else if n.Esc == EscNone {
776                 a = temp(t)
777                 if vstat == nil {
778                         a = Nod(OAS, temp(t), nil)
779                         typecheck(&a, Etop)
780                         *init = list(*init, a) // zero new temp
781                         a = a.Left
782                 }
783
784                 a = Nod(OADDR, a, nil)
785         } else {
786                 a = Nod(ONEW, nil, nil)
787                 a.List = list1(typenod(t))
788         }
789
790         a = Nod(OAS, vauto, a)
791         typecheck(&a, Etop)
792         walkexpr(&a, init)
793         *init = list(*init, a)
794
795         if vstat != nil {
796                 // copy static to heap (4)
797                 a = Nod(OIND, vauto, nil)
798
799                 a = Nod(OAS, a, vstat)
800                 typecheck(&a, Etop)
801                 walkexpr(&a, init)
802                 *init = list(*init, a)
803         }
804
805         // make slice out of heap (5)
806         a = Nod(OAS, var_, Nod(OSLICE, vauto, Nod(OKEY, nil, nil)))
807
808         typecheck(&a, Etop)
809         orderstmtinplace(&a)
810         walkstmt(&a)
811         *init = list(*init, a)
812
813         // put dynamics into slice (6)
814         for l := n.List; l != nil; l = l.Next {
815                 r := l.N
816                 if r.Op != OKEY {
817                         Fatalf("slicelit: rhs not OKEY: %v", r)
818                 }
819                 index := r.Left
820                 value := r.Right
821                 a := Nod(OINDEX, var_, index)
822                 a.Bounded = true
823
824                 // TODO need to check bounds?
825
826                 switch value.Op {
827                 case OARRAYLIT:
828                         if value.Type.Bound < 0 {
829                                 break
830                         }
831                         arraylit(ctxt, 2, value, a, init)
832                         continue
833
834                 case OSTRUCTLIT:
835                         structlit(ctxt, 2, value, a, init)
836                         continue
837                 }
838
839                 if isliteral(index) && isliteral(value) {
840                         continue
841                 }
842
843                 // build list of var[c] = expr
844                 setlineno(value)
845                 a = Nod(OAS, a, value)
846
847                 typecheck(&a, Etop)
848                 orderstmtinplace(&a)
849                 walkstmt(&a)
850                 *init = list(*init, a)
851         }
852 }
853
854 func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
855         ctxt = 0
856
857         // make the map var
858         nerr := nerrors
859
860         a := Nod(OMAKE, nil, nil)
861         a.List = list1(typenod(n.Type))
862         litas(var_, a, init)
863
864         // count the initializers
865         b := int64(0)
866
867         for l := n.List; l != nil; l = l.Next {
868                 r := l.N
869                 if r.Op != OKEY {
870                         Fatalf("maplit: rhs not OKEY: %v", r)
871                 }
872                 index := r.Left
873                 value := r.Right
874
875                 if isliteral(index) && isliteral(value) {
876                         b++
877                 }
878         }
879
880         if b != 0 {
881                 // build type [count]struct { a Tindex, b Tvalue }
882                 t := n.Type
883
884                 tk := t.Down
885                 tv := t.Type
886
887                 symb := Lookup("b")
888                 t = typ(TFIELD)
889                 t.Type = tv
890                 t.Sym = symb
891
892                 syma := Lookup("a")
893                 t1 := t
894                 t = typ(TFIELD)
895                 t.Type = tk
896                 t.Sym = syma
897                 t.Down = t1
898
899                 t1 = t
900                 t = typ(TSTRUCT)
901                 t.Type = t1
902
903                 t1 = t
904                 t = typ(TARRAY)
905                 t.Bound = b
906                 t.Type = t1
907
908                 dowidth(t)
909
910                 // make and initialize static array
911                 vstat := staticname(t, ctxt)
912
913                 b := int64(0)
914                 for l := n.List; l != nil; l = l.Next {
915                         r := l.N
916
917                         if r.Op != OKEY {
918                                 Fatalf("maplit: rhs not OKEY: %v", r)
919                         }
920                         index := r.Left
921                         value := r.Right
922
923                         if isliteral(index) && isliteral(value) {
924                                 // build vstat[b].a = key;
925                                 setlineno(index)
926                                 a = Nodintconst(b)
927
928                                 a = Nod(OINDEX, vstat, a)
929                                 a = Nod(ODOT, a, newname(syma))
930                                 a = Nod(OAS, a, index)
931                                 typecheck(&a, Etop)
932                                 walkexpr(&a, init)
933                                 a.Dodata = 2
934                                 *init = list(*init, a)
935
936                                 // build vstat[b].b = value;
937                                 setlineno(value)
938                                 a = Nodintconst(b)
939
940                                 a = Nod(OINDEX, vstat, a)
941                                 a = Nod(ODOT, a, newname(symb))
942                                 a = Nod(OAS, a, value)
943                                 typecheck(&a, Etop)
944                                 walkexpr(&a, init)
945                                 a.Dodata = 2
946                                 *init = list(*init, a)
947
948                                 b++
949                         }
950                 }
951
952                 // loop adding structure elements to map
953                 // for i = 0; i < len(vstat); i++ {
954                 //      map[vstat[i].a] = vstat[i].b
955                 // }
956                 index := temp(Types[TINT])
957
958                 a = Nod(OINDEX, vstat, index)
959                 a.Bounded = true
960                 a = Nod(ODOT, a, newname(symb))
961
962                 r := Nod(OINDEX, vstat, index)
963                 r.Bounded = true
964                 r = Nod(ODOT, r, newname(syma))
965                 r = Nod(OINDEX, var_, r)
966
967                 r = Nod(OAS, r, a)
968
969                 a = Nod(OFOR, nil, nil)
970                 a.Nbody = list1(r)
971
972                 a.Ninit = list1(Nod(OAS, index, Nodintconst(0)))
973                 a.Left = Nod(OLT, index, Nodintconst(t.Bound))
974                 a.Right = Nod(OAS, index, Nod(OADD, index, Nodintconst(1)))
975
976                 typecheck(&a, Etop)
977                 walkstmt(&a)
978                 *init = list(*init, a)
979         }
980
981         // put in dynamic entries one-at-a-time
982         var key *Node
983
984         var val *Node
985         for l := n.List; l != nil; l = l.Next {
986                 r := l.N
987
988                 if r.Op != OKEY {
989                         Fatalf("maplit: rhs not OKEY: %v", r)
990                 }
991                 index := r.Left
992                 value := r.Right
993
994                 if isliteral(index) && isliteral(value) {
995                         continue
996                 }
997
998                 // build list of var[c] = expr.
999                 // use temporary so that mapassign1 can have addressable key, val.
1000                 if key == nil {
1001                         key = temp(var_.Type.Down)
1002                         val = temp(var_.Type.Type)
1003                 }
1004
1005                 setlineno(r.Left)
1006                 a = Nod(OAS, key, r.Left)
1007                 typecheck(&a, Etop)
1008                 walkstmt(&a)
1009                 *init = list(*init, a)
1010                 setlineno(r.Right)
1011                 a = Nod(OAS, val, r.Right)
1012                 typecheck(&a, Etop)
1013                 walkstmt(&a)
1014                 *init = list(*init, a)
1015
1016                 setlineno(val)
1017                 a = Nod(OAS, Nod(OINDEX, var_, key), val)
1018                 typecheck(&a, Etop)
1019                 walkstmt(&a)
1020                 *init = list(*init, a)
1021
1022                 if nerr != nerrors {
1023                         break
1024                 }
1025         }
1026
1027         if key != nil {
1028                 a = Nod(OVARKILL, key, nil)
1029                 typecheck(&a, Etop)
1030                 *init = list(*init, a)
1031                 a = Nod(OVARKILL, val, nil)
1032                 typecheck(&a, Etop)
1033                 *init = list(*init, a)
1034         }
1035 }
1036
1037 func anylit(ctxt int, n *Node, var_ *Node, init **NodeList) {
1038         t := n.Type
1039         switch n.Op {
1040         default:
1041                 Fatalf("anylit: not lit")
1042
1043         case OPTRLIT:
1044                 if !Isptr[t.Etype] {
1045                         Fatalf("anylit: not ptr")
1046                 }
1047
1048                 var r *Node
1049                 if n.Right != nil {
1050                         r = Nod(OADDR, n.Right, nil)
1051                         typecheck(&r, Erv)
1052                 } else {
1053                         r = Nod(ONEW, nil, nil)
1054                         r.Typecheck = 1
1055                         r.Type = t
1056                         r.Esc = n.Esc
1057                 }
1058
1059                 walkexpr(&r, init)
1060                 a := Nod(OAS, var_, r)
1061
1062                 typecheck(&a, Etop)
1063                 *init = list(*init, a)
1064
1065                 var_ = Nod(OIND, var_, nil)
1066                 typecheck(&var_, Erv|Easgn)
1067                 anylit(ctxt, n.Left, var_, init)
1068
1069         case OSTRUCTLIT:
1070                 if t.Etype != TSTRUCT {
1071                         Fatalf("anylit: not struct")
1072                 }
1073
1074                 if simplename(var_) && count(n.List) > 4 {
1075                         if ctxt == 0 {
1076                                 // lay out static data
1077                                 vstat := staticname(t, ctxt)
1078
1079                                 structlit(ctxt, 1, n, vstat, init)
1080
1081                                 // copy static to var
1082                                 a := Nod(OAS, var_, vstat)
1083
1084                                 typecheck(&a, Etop)
1085                                 walkexpr(&a, init)
1086                                 *init = list(*init, a)
1087
1088                                 // add expressions to automatic
1089                                 structlit(ctxt, 2, n, var_, init)
1090
1091                                 break
1092                         }
1093
1094                         structlit(ctxt, 1, n, var_, init)
1095                         structlit(ctxt, 2, n, var_, init)
1096                         break
1097                 }
1098
1099                 // initialize of not completely specified
1100                 if simplename(var_) || count(n.List) < structcount(t) {
1101                         a := Nod(OAS, var_, nil)
1102                         typecheck(&a, Etop)
1103                         walkexpr(&a, init)
1104                         *init = list(*init, a)
1105                 }
1106
1107                 structlit(ctxt, 3, n, var_, init)
1108
1109         case OARRAYLIT:
1110                 if t.Etype != TARRAY {
1111                         Fatalf("anylit: not array")
1112                 }
1113                 if t.Bound < 0 {
1114                         slicelit(ctxt, n, var_, init)
1115                         break
1116                 }
1117
1118                 if simplename(var_) && count(n.List) > 4 {
1119                         if ctxt == 0 {
1120                                 // lay out static data
1121                                 vstat := staticname(t, ctxt)
1122
1123                                 arraylit(1, 1, n, vstat, init)
1124
1125                                 // copy static to automatic
1126                                 a := Nod(OAS, var_, vstat)
1127
1128                                 typecheck(&a, Etop)
1129                                 walkexpr(&a, init)
1130                                 *init = list(*init, a)
1131
1132                                 // add expressions to automatic
1133                                 arraylit(ctxt, 2, n, var_, init)
1134
1135                                 break
1136                         }
1137
1138                         arraylit(ctxt, 1, n, var_, init)
1139                         arraylit(ctxt, 2, n, var_, init)
1140                         break
1141                 }
1142
1143                 // initialize of not completely specified
1144                 if simplename(var_) || int64(count(n.List)) < t.Bound {
1145                         a := Nod(OAS, var_, nil)
1146                         typecheck(&a, Etop)
1147                         walkexpr(&a, init)
1148                         *init = list(*init, a)
1149                 }
1150
1151                 arraylit(ctxt, 3, n, var_, init)
1152
1153         case OMAPLIT:
1154                 if t.Etype != TMAP {
1155                         Fatalf("anylit: not map")
1156                 }
1157                 maplit(ctxt, n, var_, init)
1158         }
1159 }
1160
1161 func oaslit(n *Node, init **NodeList) bool {
1162         if n.Left == nil || n.Right == nil {
1163                 // not a special composit literal assignment
1164                 return false
1165         }
1166         if n.Left.Type == nil || n.Right.Type == nil {
1167                 // not a special composit literal assignment
1168                 return false
1169         }
1170         if !simplename(n.Left) {
1171                 // not a special composit literal assignment
1172                 return false
1173         }
1174         if !Eqtype(n.Left.Type, n.Right.Type) {
1175                 // not a special composit literal assignment
1176                 return false
1177         }
1178
1179         // context is init() function.
1180         // implies generated data executed
1181         // exactly once and not subject to races.
1182         ctxt := 0
1183
1184         //      if(n->dodata == 1)
1185         //              ctxt = 1;
1186
1187         switch n.Right.Op {
1188         default:
1189                 // not a special composit literal assignment
1190                 return false
1191
1192         case OSTRUCTLIT, OARRAYLIT, OMAPLIT:
1193                 if vmatch1(n.Left, n.Right) {
1194                         // not a special composit literal assignment
1195                         return false
1196                 }
1197                 anylit(ctxt, n.Right, n.Left, init)
1198         }
1199
1200         n.Op = OEMPTY
1201         n.Right = nil
1202         return true
1203 }
1204
1205 func getlit(lit *Node) int {
1206         if Smallintconst(lit) {
1207                 return int(Mpgetfix(lit.Val().U.(*Mpint)))
1208         }
1209         return -1
1210 }
1211
1212 // stataddr sets nam to the static address of n and reports whether it succeeeded.
1213 func stataddr(nam *Node, n *Node) bool {
1214         if n == nil {
1215                 return false
1216         }
1217
1218         switch n.Op {
1219         case ONAME:
1220                 *nam = *n
1221                 return n.Addable
1222
1223         case ODOT:
1224                 if !stataddr(nam, n.Left) {
1225                         break
1226                 }
1227                 nam.Xoffset += n.Xoffset
1228                 nam.Type = n.Type
1229                 return true
1230
1231         case OINDEX:
1232                 if n.Left.Type.Bound < 0 {
1233                         break
1234                 }
1235                 if !stataddr(nam, n.Left) {
1236                         break
1237                 }
1238                 l := getlit(n.Right)
1239                 if l < 0 {
1240                         break
1241                 }
1242
1243                 // Check for overflow.
1244                 if n.Type.Width != 0 && Thearch.MAXWIDTH/n.Type.Width <= int64(l) {
1245                         break
1246                 }
1247                 nam.Xoffset += int64(l) * n.Type.Width
1248                 nam.Type = n.Type
1249                 return true
1250         }
1251
1252         return false
1253 }
1254
1255 func initplan(n *Node) {
1256         if initplans[n] != nil {
1257                 return
1258         }
1259         p := new(InitPlan)
1260         initplans[n] = p
1261         switch n.Op {
1262         default:
1263                 Fatalf("initplan")
1264
1265         case OARRAYLIT:
1266                 for l := n.List; l != nil; l = l.Next {
1267                         a := l.N
1268                         if a.Op != OKEY || !Smallintconst(a.Left) {
1269                                 Fatalf("initplan arraylit")
1270                         }
1271                         addvalue(p, n.Type.Type.Width*Mpgetfix(a.Left.Val().U.(*Mpint)), nil, a.Right)
1272                 }
1273
1274         case OSTRUCTLIT:
1275                 for l := n.List; l != nil; l = l.Next {
1276                         a := l.N
1277                         if a.Op != OKEY || a.Left.Type == nil {
1278                                 Fatalf("initplan structlit")
1279                         }
1280                         addvalue(p, a.Left.Type.Width, nil, a.Right)
1281                 }
1282
1283         case OMAPLIT:
1284                 for l := n.List; l != nil; l = l.Next {
1285                         a := l.N
1286                         if a.Op != OKEY {
1287                                 Fatalf("initplan maplit")
1288                         }
1289                         addvalue(p, -1, a.Left, a.Right)
1290                 }
1291         }
1292 }
1293
1294 func addvalue(p *InitPlan, xoffset int64, key *Node, n *Node) {
1295         // special case: zero can be dropped entirely
1296         if iszero(n) {
1297                 p.Zero += n.Type.Width
1298                 return
1299         }
1300
1301         // special case: inline struct and array (not slice) literals
1302         if isvaluelit(n) {
1303                 initplan(n)
1304                 q := initplans[n]
1305                 for _, qe := range q.E {
1306                         e := entry(p)
1307                         *e = qe
1308                         e.Xoffset += xoffset
1309                 }
1310                 return
1311         }
1312
1313         // add to plan
1314         if n.Op == OLITERAL {
1315                 p.Lit += n.Type.Width
1316         } else {
1317                 p.Expr += n.Type.Width
1318         }
1319
1320         e := entry(p)
1321         e.Xoffset = xoffset
1322         e.Expr = n
1323 }
1324
1325 func iszero(n *Node) bool {
1326         switch n.Op {
1327         case OLITERAL:
1328                 switch n.Val().Ctype() {
1329                 default:
1330                         Dump("unexpected literal", n)
1331                         Fatalf("iszero")
1332
1333                 case CTNIL:
1334                         return true
1335
1336                 case CTSTR:
1337                         return n.Val().U.(string) == ""
1338
1339                 case CTBOOL:
1340                         return !n.Val().U.(bool)
1341
1342                 case CTINT, CTRUNE:
1343                         return mpcmpfixc(n.Val().U.(*Mpint), 0) == 0
1344
1345                 case CTFLT:
1346                         return mpcmpfltc(n.Val().U.(*Mpflt), 0) == 0
1347
1348                 case CTCPLX:
1349                         return mpcmpfltc(&n.Val().U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&n.Val().U.(*Mpcplx).Imag, 0) == 0
1350                 }
1351
1352         case OARRAYLIT:
1353                 if Isslice(n.Type) {
1354                         break
1355                 }
1356                 fallthrough
1357
1358                 // fall through
1359         case OSTRUCTLIT:
1360                 for l := n.List; l != nil; l = l.Next {
1361                         if !iszero(l.N.Right) {
1362                                 return false
1363                         }
1364                 }
1365                 return true
1366         }
1367
1368         return false
1369 }
1370
1371 func isvaluelit(n *Node) bool {
1372         return (n.Op == OARRAYLIT && Isfixedarray(n.Type)) || n.Op == OSTRUCTLIT
1373 }
1374
1375 func entry(p *InitPlan) *InitEntry {
1376         p.E = append(p.E, InitEntry{})
1377         return &p.E[len(p.E)-1]
1378 }
1379
1380 // gen_as_init attempts to emit static data for n and reports whether it succeeded.
1381 // If reportOnly is true, it does not emit static data and does not modify the AST.
1382 func gen_as_init(n *Node, reportOnly bool) bool {
1383         var nr *Node
1384         var nl *Node
1385         var nam Node
1386
1387         if n.Dodata == 0 {
1388                 goto no
1389         }
1390
1391         nr = n.Right
1392         nl = n.Left
1393         if nr == nil {
1394                 var nam Node
1395                 if !stataddr(&nam, nl) {
1396                         goto no
1397                 }
1398                 if nam.Class != PEXTERN {
1399                         goto no
1400                 }
1401                 return true
1402         }
1403
1404         if nr.Type == nil || !Eqtype(nl.Type, nr.Type) {
1405                 goto no
1406         }
1407
1408         if !stataddr(&nam, nl) {
1409                 goto no
1410         }
1411
1412         if nam.Class != PEXTERN {
1413                 goto no
1414         }
1415
1416         switch nr.Op {
1417         default:
1418                 goto no
1419
1420         case OCONVNOP:
1421                 nr = nr.Left
1422                 if nr == nil || nr.Op != OSLICEARR {
1423                         goto no
1424                 }
1425                 fallthrough
1426
1427                 // fall through
1428         case OSLICEARR:
1429                 if nr.Right.Op == OKEY && nr.Right.Left == nil && nr.Right.Right == nil {
1430                         nr = nr.Left
1431                         nl := nr
1432                         if nr == nil || nr.Op != OADDR {
1433                                 goto no
1434                         }
1435                         nr = nr.Left
1436                         if nr == nil || nr.Op != ONAME {
1437                                 goto no
1438                         }
1439
1440                         // nr is the array being converted to a slice
1441                         if nr.Type == nil || nr.Type.Etype != TARRAY || nr.Type.Bound < 0 {
1442                                 goto no
1443                         }
1444
1445                         if !reportOnly {
1446                                 nam.Xoffset += int64(Array_array)
1447                                 gdata(&nam, nl, int(Types[Tptr].Width))
1448
1449                                 nam.Xoffset += int64(Array_nel) - int64(Array_array)
1450                                 var nod1 Node
1451                                 Nodconst(&nod1, Types[TINT], nr.Type.Bound)
1452                                 gdata(&nam, &nod1, Widthint)
1453
1454                                 nam.Xoffset += int64(Array_cap) - int64(Array_nel)
1455                                 gdata(&nam, &nod1, Widthint)
1456                         }
1457
1458                         return true
1459                 }
1460
1461                 goto no
1462
1463         case OLITERAL:
1464                 break
1465         }
1466
1467         switch nr.Type.Etype {
1468         default:
1469                 goto no
1470
1471         case TBOOL,
1472                 TINT8,
1473                 TUINT8,
1474                 TINT16,
1475                 TUINT16,
1476                 TINT32,
1477                 TUINT32,
1478                 TINT64,
1479                 TUINT64,
1480                 TINT,
1481                 TUINT,
1482                 TUINTPTR,
1483                 TPTR32,
1484                 TPTR64,
1485                 TFLOAT32,
1486                 TFLOAT64:
1487                 if !reportOnly {
1488                         gdata(&nam, nr, int(nr.Type.Width))
1489                 }
1490
1491         case TCOMPLEX64, TCOMPLEX128:
1492                 if !reportOnly {
1493                         gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
1494                 }
1495
1496         case TSTRING:
1497                 if !reportOnly {
1498                         gdatastring(&nam, nr.Val().U.(string))
1499                 }
1500         }
1501
1502         return true
1503
1504 no:
1505         if n.Dodata == 2 {
1506                 Dump("\ngen_as_init", n)
1507                 Fatalf("gen_as_init couldnt make data statement")
1508         }
1509
1510         return false
1511 }