]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/gc/pgen.go
[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch
[gostls13.git] / src / cmd / compile / internal / gc / pgen.go
1 // Copyright 2011 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/compile/internal/ssa"
9         "cmd/internal/obj"
10         "crypto/md5"
11         "fmt"
12         "strings"
13 )
14
15 // "Portable" code generation.
16
17 var makefuncdatasym_nsym int32
18
19 func makefuncdatasym(namefmt string, funcdatakind int64) *Sym {
20         var nod Node
21
22         sym := Lookupf(namefmt, makefuncdatasym_nsym)
23         makefuncdatasym_nsym++
24         pnod := newname(sym)
25         pnod.Class = PEXTERN
26         Nodconst(&nod, Types[TINT32], funcdatakind)
27         Thearch.Gins(obj.AFUNCDATA, &nod, pnod)
28         return sym
29 }
30
31 // gvardef inserts a VARDEF for n into the instruction stream.
32 // VARDEF is an annotation for the liveness analysis, marking a place
33 // where a complete initialization (definition) of a variable begins.
34 // Since the liveness analysis can see initialization of single-word
35 // variables quite easy, gvardef is usually only called for multi-word
36 // or 'fat' variables, those satisfying isfat(n->type).
37 // However, gvardef is also called when a non-fat variable is initialized
38 // via a block move; the only time this happens is when you have
39 //      return f()
40 // for a function with multiple return values exactly matching the return
41 // types of the current function.
42 //
43 // A 'VARDEF x' annotation in the instruction stream tells the liveness
44 // analysis to behave as though the variable x is being initialized at that
45 // point in the instruction stream. The VARDEF must appear before the
46 // actual (multi-instruction) initialization, and it must also appear after
47 // any uses of the previous value, if any. For example, if compiling:
48 //
49 //      x = x[1:]
50 //
51 // it is important to generate code like:
52 //
53 //      base, len, cap = pieces of x[1:]
54 //      VARDEF x
55 //      x = {base, len, cap}
56 //
57 // If instead the generated code looked like:
58 //
59 //      VARDEF x
60 //      base, len, cap = pieces of x[1:]
61 //      x = {base, len, cap}
62 //
63 // then the liveness analysis would decide the previous value of x was
64 // unnecessary even though it is about to be used by the x[1:] computation.
65 // Similarly, if the generated code looked like:
66 //
67 //      base, len, cap = pieces of x[1:]
68 //      x = {base, len, cap}
69 //      VARDEF x
70 //
71 // then the liveness analysis will not preserve the new value of x, because
72 // the VARDEF appears to have "overwritten" it.
73 //
74 // VARDEF is a bit of a kludge to work around the fact that the instruction
75 // stream is working on single-word values but the liveness analysis
76 // wants to work on individual variables, which might be multi-word
77 // aggregates. It might make sense at some point to look into letting
78 // the liveness analysis work on single-word values as well, although
79 // there are complications around interface values, slices, and strings,
80 // all of which cannot be treated as individual words.
81 //
82 // VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
83 // even if its address has been taken. That is, a VARKILL annotation asserts
84 // that its argument is certainly dead, for use when the liveness analysis
85 // would not otherwise be able to deduce that fact.
86
87 func gvardefx(n *Node, as int) {
88         if n == nil {
89                 Fatalf("gvardef nil")
90         }
91         if n.Op != ONAME {
92                 Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), n)
93                 return
94         }
95
96         switch n.Class {
97         case PAUTO, PPARAM, PPARAMOUT:
98                 Thearch.Gins(as, nil, n)
99         }
100 }
101
102 func Gvardef(n *Node) {
103         gvardefx(n, obj.AVARDEF)
104 }
105
106 func gvarkill(n *Node) {
107         gvardefx(n, obj.AVARKILL)
108 }
109
110 func removevardef(firstp *obj.Prog) {
111         for p := firstp; p != nil; p = p.Link {
112                 for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL) {
113                         p.Link = p.Link.Link
114                 }
115                 if p.To.Type == obj.TYPE_BRANCH {
116                         for p.To.Val.(*obj.Prog) != nil && (p.To.Val.(*obj.Prog).As == obj.AVARDEF || p.To.Val.(*obj.Prog).As == obj.AVARKILL) {
117                                 p.To.Val = p.To.Val.(*obj.Prog).Link
118                         }
119                 }
120         }
121 }
122
123 func gcsymdup(s *Sym) {
124         ls := Linksym(s)
125         if len(ls.R) > 0 {
126                 Fatalf("cannot rosymdup %s with relocations", ls.Name)
127         }
128         ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P))
129         ls.Dupok = 1
130 }
131
132 func emitptrargsmap() {
133         sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
134
135         nptr := int(Curfn.Type.Argwid / int64(Widthptr))
136         bv := bvalloc(int32(nptr) * 2)
137         nbitmap := 1
138         if Curfn.Type.Outtuple > 0 {
139                 nbitmap = 2
140         }
141         off := duint32(sym, 0, uint32(nbitmap))
142         off = duint32(sym, off, uint32(bv.n))
143         var xoffset int64
144         if Curfn.Type.Thistuple > 0 {
145                 xoffset = 0
146                 onebitwalktype1(getthisx(Curfn.Type), &xoffset, bv)
147         }
148
149         if Curfn.Type.Intuple > 0 {
150                 xoffset = 0
151                 onebitwalktype1(getinargx(Curfn.Type), &xoffset, bv)
152         }
153
154         for j := 0; int32(j) < bv.n; j += 32 {
155                 off = duint32(sym, off, bv.b[j/32])
156         }
157         if Curfn.Type.Outtuple > 0 {
158                 xoffset = 0
159                 onebitwalktype1(getoutargx(Curfn.Type), &xoffset, bv)
160                 for j := 0; int32(j) < bv.n; j += 32 {
161                         off = duint32(sym, off, bv.b[j/32])
162                 }
163         }
164
165         ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
166 }
167
168 // cmpstackvarlt reports whether the stack variable a sorts before b.
169 //
170 // Sort the list of stack variables. Autos after anything else,
171 // within autos, unused after used, within used, things with
172 // pointers first, zeroed things first, and then decreasing size.
173 // Because autos are laid out in decreasing addresses
174 // on the stack, pointers first, zeroed things first and decreasing size
175 // really means, in memory, things with pointers needing zeroing at
176 // the top of the stack and increasing in size.
177 // Non-autos sort on offset.
178 func cmpstackvarlt(a, b *Node) bool {
179         if a.Class != b.Class {
180                 if a.Class == PAUTO {
181                         return false
182                 }
183                 return true
184         }
185
186         if a.Class != PAUTO {
187                 if a.Xoffset < b.Xoffset {
188                         return true
189                 }
190                 if a.Xoffset > b.Xoffset {
191                         return false
192                 }
193                 return false
194         }
195
196         if a.Used != b.Used {
197                 return a.Used
198         }
199
200         ap := haspointers(a.Type)
201         bp := haspointers(b.Type)
202         if ap != bp {
203                 return ap
204         }
205
206         ap = a.Name.Needzero
207         bp = b.Name.Needzero
208         if ap != bp {
209                 return ap
210         }
211
212         if a.Type.Width < b.Type.Width {
213                 return false
214         }
215         if a.Type.Width > b.Type.Width {
216                 return true
217         }
218
219         return a.Sym.Name < b.Sym.Name
220 }
221
222 // stkdelta records the stack offset delta for a node
223 // during the compaction of the stack frame to remove
224 // unused stack slots.
225 var stkdelta = map[*Node]int64{}
226
227 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
228 func allocauto(ptxt *obj.Prog) {
229         Stksize = 0
230         stkptrsize = 0
231
232         if Curfn.Func.Dcl == nil {
233                 return
234         }
235
236         // Mark the PAUTO's unused.
237         for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
238                 if ll.N.Class == PAUTO {
239                         ll.N.Used = false
240                 }
241         }
242
243         markautoused(ptxt)
244
245         listsort(&Curfn.Func.Dcl, cmpstackvarlt)
246
247         // Unused autos are at the end, chop 'em off.
248         ll := Curfn.Func.Dcl
249
250         n := ll.N
251         if n.Class == PAUTO && n.Op == ONAME && !n.Used {
252                 // No locals used at all
253                 Curfn.Func.Dcl = nil
254
255                 fixautoused(ptxt)
256                 return
257         }
258
259         for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next {
260                 n = ll.Next.N
261                 if n.Class == PAUTO && n.Op == ONAME && !n.Used {
262                         ll.Next = nil
263                         Curfn.Func.Dcl.End = ll
264                         break
265                 }
266         }
267
268         // Reassign stack offsets of the locals that are still there.
269         var w int64
270         for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
271                 n = ll.N
272                 if n.Class != PAUTO || n.Op != ONAME {
273                         continue
274                 }
275
276                 dowidth(n.Type)
277                 w = n.Type.Width
278                 if w >= Thearch.MAXWIDTH || w < 0 {
279                         Fatalf("bad width")
280                 }
281                 Stksize += w
282                 Stksize = Rnd(Stksize, int64(n.Type.Align))
283                 if haspointers(n.Type) {
284                         stkptrsize = Stksize
285                 }
286                 if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
287                         Stksize = Rnd(Stksize, int64(Widthptr))
288                 }
289                 if Stksize >= 1<<31 {
290                         setlineno(Curfn)
291                         Yyerror("stack frame too large (>2GB)")
292                 }
293
294                 stkdelta[n] = -Stksize - n.Xoffset
295         }
296
297         Stksize = Rnd(Stksize, int64(Widthreg))
298         stkptrsize = Rnd(stkptrsize, int64(Widthreg))
299
300         fixautoused(ptxt)
301
302         // The debug information needs accurate offsets on the symbols.
303         for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
304                 if ll.N.Class != PAUTO || ll.N.Op != ONAME {
305                         continue
306                 }
307                 ll.N.Xoffset += stkdelta[ll.N]
308                 delete(stkdelta, ll.N)
309         }
310 }
311
312 func Cgen_checknil(n *Node) {
313         if Disable_checknil != 0 {
314                 return
315         }
316
317         // Ideally we wouldn't see any integer types here, but we do.
318         if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) {
319                 Dump("checknil", n)
320                 Fatalf("bad checknil")
321         }
322
323         if ((Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
324                 var reg Node
325                 Regalloc(&reg, Types[Tptr], n)
326                 Cgen(n, &reg)
327                 Thearch.Gins(obj.ACHECKNIL, &reg, nil)
328                 Regfree(&reg)
329                 return
330         }
331
332         Thearch.Gins(obj.ACHECKNIL, n, nil)
333 }
334
335 func compile(fn *Node) {
336         if Newproc == nil {
337                 Newproc = Sysfunc("newproc")
338                 Deferproc = Sysfunc("deferproc")
339                 Deferreturn = Sysfunc("deferreturn")
340                 Panicindex = Sysfunc("panicindex")
341                 panicslice = Sysfunc("panicslice")
342                 throwreturn = Sysfunc("throwreturn")
343                 growslice = Sysfunc("growslice")
344                 typedmemmove_nostore = Sysfunc("typedmemmove_nostore")
345                 panicdottype = Sysfunc("panicdottype")
346         }
347
348         lno := setlineno(fn)
349
350         Curfn = fn
351         dowidth(Curfn.Type)
352
353         var oldstksize int64
354         var nod1 Node
355         var ptxt *obj.Prog
356         var pl *obj.Plist
357         var p *obj.Prog
358         var n *Node
359         var nam *Node
360         var gcargs *Sym
361         var gclocals *Sym
362         var ssafn *ssa.Func
363         var usessa bool
364         if fn.Nbody == nil {
365                 if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
366                         Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
367                         goto ret
368                 }
369
370                 if Debug['A'] != 0 {
371                         goto ret
372                 }
373                 emitptrargsmap()
374                 goto ret
375         }
376
377         saveerrors()
378
379         // set up domain for labels
380         clearlabels()
381
382         if Curfn.Type.Outnamed {
383                 // add clearing of the output parameters
384                 var save Iter
385                 t := Structfirst(&save, Getoutarg(Curfn.Type))
386
387                 for t != nil {
388                         if t.Nname != nil {
389                                 n = Nod(OAS, t.Nname, nil)
390                                 typecheck(&n, Etop)
391                                 Curfn.Nbody = concat(list1(n), Curfn.Nbody)
392                         }
393
394                         t = structnext(&save)
395                 }
396         }
397
398         order(Curfn)
399         if nerrors != 0 {
400                 goto ret
401         }
402
403         hasdefer = false
404         walk(Curfn)
405         if nerrors != 0 {
406                 goto ret
407         }
408         if flag_race != 0 {
409                 racewalk(Curfn)
410         }
411         if nerrors != 0 {
412                 goto ret
413         }
414
415         // Build an SSA backend function.
416         // TODO: get rid of usessa.
417         ssafn, usessa = buildssa(Curfn)
418
419         continpc = nil
420         breakpc = nil
421
422         pl = newplist()
423         pl.Name = Linksym(Curfn.Func.Nname.Sym)
424
425         setlineno(Curfn)
426
427         Nodconst(&nod1, Types[TINT32], 0)
428         nam = Curfn.Func.Nname
429         if isblank(nam) {
430                 nam = nil
431         }
432         ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
433         Afunclit(&ptxt.From, Curfn.Func.Nname)
434         ptxt.From3 = new(obj.Addr)
435         if fn.Func.Dupok {
436                 ptxt.From3.Offset |= obj.DUPOK
437         }
438         if fn.Func.Wrapper {
439                 ptxt.From3.Offset |= obj.WRAPPER
440         }
441         if fn.Func.Needctxt {
442                 ptxt.From3.Offset |= obj.NEEDCTXT
443         }
444         if fn.Func.Nosplit {
445                 ptxt.From3.Offset |= obj.NOSPLIT
446         }
447         if fn.Func.Systemstack {
448                 ptxt.From.Sym.Cfunc = 1
449         }
450
451         // Clumsy but important.
452         // See test/recover.go for test cases and src/reflect/value.go
453         // for the actual functions being considered.
454         if myimportpath != "" && myimportpath == "reflect" {
455                 if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
456                         ptxt.From3.Offset |= obj.WRAPPER
457                 }
458         }
459
460         ginit()
461
462         gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
463         gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)
464
465         for _, t := range Curfn.Func.Fieldtrack {
466                 gtrack(tracksym(t))
467         }
468
469         for l := fn.Func.Dcl; l != nil; l = l.Next {
470                 n = l.N
471                 if n.Op != ONAME { // might be OTYPE or OLITERAL
472                         continue
473                 }
474                 switch n.Class {
475                 case PAUTO, PPARAM, PPARAMOUT:
476                         Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width)
477                         p = Thearch.Gins(obj.ATYPE, l.N, &nod1)
478                         p.From.Gotype = Linksym(ngotype(l.N))
479                 }
480         }
481
482         if ssafn != nil && usessa {
483                 genssa(ssafn, ptxt, gcargs, gclocals)
484                 return
485         }
486         Genlist(Curfn.Func.Enter)
487         Genlist(Curfn.Nbody)
488         gclean()
489         checklabels()
490         if nerrors != 0 {
491                 goto ret
492         }
493         if Curfn.Func.Endlineno != 0 {
494                 lineno = Curfn.Func.Endlineno
495         }
496
497         if Curfn.Type.Outtuple != 0 {
498                 Ginscall(throwreturn, 0)
499         }
500
501         ginit()
502
503         // TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
504         cgen_ret(nil)
505
506         if hasdefer {
507                 // deferreturn pretends to have one uintptr argument.
508                 // Reserve space for it so stack scanner is happy.
509                 if Maxarg < int64(Widthptr) {
510                         Maxarg = int64(Widthptr)
511                 }
512         }
513
514         gclean()
515         if nerrors != 0 {
516                 goto ret
517         }
518
519         Pc.As = obj.ARET // overwrite AEND
520         Pc.Lineno = lineno
521
522         fixjmp(ptxt)
523         if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
524                 regopt(ptxt)
525                 nilopt(ptxt)
526         }
527
528         Thearch.Expandchecks(ptxt)
529
530         oldstksize = Stksize
531         allocauto(ptxt)
532
533         if false {
534                 fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize))
535         }
536
537         setlineno(Curfn)
538         if int64(Stksize)+Maxarg > 1<<31 {
539                 Yyerror("stack frame too large (>2GB)")
540                 goto ret
541         }
542
543         // Emit garbage collection symbols.
544         liveness(Curfn, ptxt, gcargs, gclocals)
545
546         gcsymdup(gcargs)
547         gcsymdup(gclocals)
548
549         Thearch.Defframe(ptxt)
550
551         if Debug['f'] != 0 {
552                 frame(0)
553         }
554
555         // Remove leftover instrumentation from the instruction stream.
556         removevardef(ptxt)
557
558 ret:
559         lineno = lno
560 }