]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/gc/pgen.go
[dev.ssa] Merge remote-tracking branch 'origin/master' into ssamerge
[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                 Fatal("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                 Fatal("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 // Sort the list of stack variables. Autos after anything else,
169 // within autos, unused after used, within used, things with
170 // pointers first, zeroed things first, and then decreasing size.
171 // Because autos are laid out in decreasing addresses
172 // on the stack, pointers first, zeroed things first and decreasing size
173 // really means, in memory, things with pointers needing zeroing at
174 // the top of the stack and increasing in size.
175 // Non-autos sort on offset.
176 func cmpstackvar(a *Node, b *Node) int {
177         if a.Class != b.Class {
178                 if a.Class == PAUTO {
179                         return +1
180                 }
181                 return -1
182         }
183
184         if a.Class != PAUTO {
185                 if a.Xoffset < b.Xoffset {
186                         return -1
187                 }
188                 if a.Xoffset > b.Xoffset {
189                         return +1
190                 }
191                 return 0
192         }
193
194         if a.Used != b.Used {
195                 return obj.Bool2int(b.Used) - obj.Bool2int(a.Used)
196         }
197
198         ap := obj.Bool2int(haspointers(a.Type))
199         bp := obj.Bool2int(haspointers(b.Type))
200         if ap != bp {
201                 return bp - ap
202         }
203
204         ap = obj.Bool2int(a.Name.Needzero)
205         bp = obj.Bool2int(b.Name.Needzero)
206         if ap != bp {
207                 return bp - ap
208         }
209
210         if a.Type.Width < b.Type.Width {
211                 return +1
212         }
213         if a.Type.Width > b.Type.Width {
214                 return -1
215         }
216
217         return stringsCompare(a.Sym.Name, b.Sym.Name)
218 }
219
220 // stkdelta records the stack offset delta for a node
221 // during the compaction of the stack frame to remove
222 // unused stack slots.
223 var stkdelta = map[*Node]int64{}
224
225 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
226 func allocauto(ptxt *obj.Prog) {
227         Stksize = 0
228         stkptrsize = 0
229
230         if Curfn.Func.Dcl == nil {
231                 return
232         }
233
234         // Mark the PAUTO's unused.
235         for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
236                 if ll.N.Class == PAUTO {
237                         ll.N.Used = false
238                 }
239         }
240
241         markautoused(ptxt)
242
243         listsort(&Curfn.Func.Dcl, cmpstackvar)
244
245         // Unused autos are at the end, chop 'em off.
246         ll := Curfn.Func.Dcl
247
248         n := ll.N
249         if n.Class == PAUTO && n.Op == ONAME && !n.Used {
250                 // No locals used at all
251                 Curfn.Func.Dcl = nil
252
253                 fixautoused(ptxt)
254                 return
255         }
256
257         for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next {
258                 n = ll.Next.N
259                 if n.Class == PAUTO && n.Op == ONAME && !n.Used {
260                         ll.Next = nil
261                         Curfn.Func.Dcl.End = ll
262                         break
263                 }
264         }
265
266         // Reassign stack offsets of the locals that are still there.
267         var w int64
268         for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
269                 n = ll.N
270                 if n.Class != PAUTO || n.Op != ONAME {
271                         continue
272                 }
273
274                 dowidth(n.Type)
275                 w = n.Type.Width
276                 if w >= Thearch.MAXWIDTH || w < 0 {
277                         Fatal("bad width")
278                 }
279                 Stksize += w
280                 Stksize = Rnd(Stksize, int64(n.Type.Align))
281                 if haspointers(n.Type) {
282                         stkptrsize = Stksize
283                 }
284                 if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
285                         Stksize = Rnd(Stksize, int64(Widthptr))
286                 }
287                 if Stksize >= 1<<31 {
288                         setlineno(Curfn)
289                         Yyerror("stack frame too large (>2GB)")
290                 }
291
292                 stkdelta[n] = -Stksize - n.Xoffset
293         }
294
295         Stksize = Rnd(Stksize, int64(Widthreg))
296         stkptrsize = Rnd(stkptrsize, int64(Widthreg))
297
298         fixautoused(ptxt)
299
300         // The debug information needs accurate offsets on the symbols.
301         for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
302                 if ll.N.Class != PAUTO || ll.N.Op != ONAME {
303                         continue
304                 }
305                 ll.N.Xoffset += stkdelta[ll.N]
306                 delete(stkdelta, ll.N)
307         }
308 }
309
310 func Cgen_checknil(n *Node) {
311         if Disable_checknil != 0 {
312                 return
313         }
314
315         // Ideally we wouldn't see any integer types here, but we do.
316         if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) {
317                 Dump("checknil", n)
318                 Fatal("bad checknil")
319         }
320
321         if ((Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
322                 var reg Node
323                 Regalloc(&reg, Types[Tptr], n)
324                 Cgen(n, &reg)
325                 Thearch.Gins(obj.ACHECKNIL, &reg, nil)
326                 Regfree(&reg)
327                 return
328         }
329
330         Thearch.Gins(obj.ACHECKNIL, n, nil)
331 }
332
333 func compile(fn *Node) {
334         if Newproc == nil {
335                 Newproc = Sysfunc("newproc")
336                 Deferproc = Sysfunc("deferproc")
337                 Deferreturn = Sysfunc("deferreturn")
338                 Panicindex = Sysfunc("panicindex")
339                 panicslice = Sysfunc("panicslice")
340                 throwreturn = Sysfunc("throwreturn")
341         }
342
343         lno := setlineno(fn)
344
345         Curfn = fn
346         dowidth(Curfn.Type)
347
348         var oldstksize int64
349         var nod1 Node
350         var ptxt *obj.Prog
351         var pl *obj.Plist
352         var p *obj.Prog
353         var n *Node
354         var nam *Node
355         var gcargs *Sym
356         var gclocals *Sym
357         var ssafn *ssa.Func
358         var usessa bool
359         if fn.Nbody == nil {
360                 if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
361                         Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
362                         goto ret
363                 }
364
365                 if Debug['A'] != 0 {
366                         goto ret
367                 }
368                 emitptrargsmap()
369                 goto ret
370         }
371
372         saveerrors()
373
374         // set up domain for labels
375         clearlabels()
376
377         if Curfn.Type.Outnamed != 0 {
378                 // add clearing of the output parameters
379                 var save Iter
380                 t := Structfirst(&save, Getoutarg(Curfn.Type))
381
382                 for t != nil {
383                         if t.Nname != nil {
384                                 n = Nod(OAS, t.Nname, nil)
385                                 typecheck(&n, Etop)
386                                 Curfn.Nbody = concat(list1(n), Curfn.Nbody)
387                         }
388
389                         t = structnext(&save)
390                 }
391         }
392
393         order(Curfn)
394         if nerrors != 0 {
395                 goto ret
396         }
397
398         Hasdefer = 0
399         walk(Curfn)
400         if nerrors != 0 {
401                 goto ret
402         }
403         if flag_race != 0 {
404                 racewalk(Curfn)
405         }
406         if nerrors != 0 {
407                 goto ret
408         }
409
410         // Build an SSA backend function.
411         // TODO: get rid of usessa.
412         ssafn, usessa = buildssa(Curfn)
413
414         continpc = nil
415         breakpc = nil
416
417         pl = newplist()
418         pl.Name = Linksym(Curfn.Func.Nname.Sym)
419
420         setlineno(Curfn)
421
422         Nodconst(&nod1, Types[TINT32], 0)
423         nam = Curfn.Func.Nname
424         if isblank(nam) {
425                 nam = nil
426         }
427         ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
428         Afunclit(&ptxt.From, Curfn.Func.Nname)
429         ptxt.From3 = new(obj.Addr)
430         if fn.Func.Dupok {
431                 ptxt.From3.Offset |= obj.DUPOK
432         }
433         if fn.Func.Wrapper {
434                 ptxt.From3.Offset |= obj.WRAPPER
435         }
436         if fn.Func.Needctxt {
437                 ptxt.From3.Offset |= obj.NEEDCTXT
438         }
439         if fn.Func.Nosplit {
440                 ptxt.From3.Offset |= obj.NOSPLIT
441         }
442         if fn.Func.Systemstack {
443                 ptxt.From.Sym.Cfunc = 1
444         }
445
446         // Clumsy but important.
447         // See test/recover.go for test cases and src/reflect/value.go
448         // for the actual functions being considered.
449         if myimportpath != "" && myimportpath == "reflect" {
450                 if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
451                         ptxt.From3.Offset |= obj.WRAPPER
452                 }
453         }
454
455         ginit()
456
457         gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
458         gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)
459
460         for _, t := range Curfn.Func.Fieldtrack {
461                 gtrack(tracksym(t))
462         }
463
464         for l := fn.Func.Dcl; l != nil; l = l.Next {
465                 n = l.N
466                 if n.Op != ONAME { // might be OTYPE or OLITERAL
467                         continue
468                 }
469                 switch n.Class {
470                 case PAUTO, PPARAM, PPARAMOUT:
471                         Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width)
472                         p = Thearch.Gins(obj.ATYPE, l.N, &nod1)
473                         p.From.Gotype = Linksym(ngotype(l.N))
474                 }
475         }
476
477         if ssafn != nil && usessa {
478                 genssa(ssafn, ptxt, gcargs, gclocals)
479                 return
480         }
481         Genlist(Curfn.Func.Enter)
482         Genlist(Curfn.Nbody)
483         gclean()
484         checklabels()
485         if nerrors != 0 {
486                 goto ret
487         }
488         if Curfn.Func.Endlineno != 0 {
489                 lineno = Curfn.Func.Endlineno
490         }
491
492         if Curfn.Type.Outtuple != 0 {
493                 Ginscall(throwreturn, 0)
494         }
495
496         ginit()
497
498         // TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
499         cgen_ret(nil)
500
501         if Hasdefer != 0 {
502                 // deferreturn pretends to have one uintptr argument.
503                 // Reserve space for it so stack scanner is happy.
504                 if Maxarg < int64(Widthptr) {
505                         Maxarg = int64(Widthptr)
506                 }
507         }
508
509         gclean()
510         if nerrors != 0 {
511                 goto ret
512         }
513
514         Pc.As = obj.ARET // overwrite AEND
515         Pc.Lineno = lineno
516
517         fixjmp(ptxt)
518         if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
519                 regopt(ptxt)
520                 nilopt(ptxt)
521         }
522
523         Thearch.Expandchecks(ptxt)
524
525         oldstksize = Stksize
526         allocauto(ptxt)
527
528         if false {
529                 fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize))
530         }
531
532         setlineno(Curfn)
533         if int64(Stksize)+Maxarg > 1<<31 {
534                 Yyerror("stack frame too large (>2GB)")
535                 goto ret
536         }
537
538         // Emit garbage collection symbols.
539         liveness(Curfn, ptxt, gcargs, gclocals)
540
541         gcsymdup(gcargs)
542         gcsymdup(gclocals)
543
544         Thearch.Defframe(ptxt)
545
546         if Debug['f'] != 0 {
547                 frame(0)
548         }
549
550         // Remove leftover instrumentation from the instruction stream.
551         removevardef(ptxt)
552
553 ret:
554         lineno = lno
555 }