Source file src/pkg/cmd/compile/internal/gc/pgen.go
1
2
3
4
5 package gc
6
7 import (
8 "cmd/compile/internal/ssa"
9 "cmd/compile/internal/types"
10 "cmd/internal/dwarf"
11 "cmd/internal/obj"
12 "cmd/internal/objabi"
13 "cmd/internal/src"
14 "cmd/internal/sys"
15 "fmt"
16 "internal/race"
17 "math/rand"
18 "sort"
19 "sync"
20 "time"
21 )
22
23
24
25 var (
26 nBackendWorkers int
27 compilequeue []*Node
28 )
29
30 func emitptrargsmap(fn *Node) {
31 if fn.funcname() == "_" {
32 return
33 }
34 sym := lookup(fmt.Sprintf("%s.args_stackmap", fn.funcname()))
35 lsym := sym.Linksym()
36
37 nptr := int(fn.Type.ArgWidth() / int64(Widthptr))
38 bv := bvalloc(int32(nptr) * 2)
39 nbitmap := 1
40 if fn.Type.NumResults() > 0 {
41 nbitmap = 2
42 }
43 off := duint32(lsym, 0, uint32(nbitmap))
44 off = duint32(lsym, off, uint32(bv.n))
45
46 if fn.IsMethod() {
47 onebitwalktype1(fn.Type.Recvs(), 0, bv)
48 }
49 if fn.Type.NumParams() > 0 {
50 onebitwalktype1(fn.Type.Params(), 0, bv)
51 }
52 off = dbvec(lsym, off, bv)
53
54 if fn.Type.NumResults() > 0 {
55 onebitwalktype1(fn.Type.Results(), 0, bv)
56 off = dbvec(lsym, off, bv)
57 }
58
59 ggloblsym(lsym, int32(off), obj.RODATA|obj.LOCAL)
60 }
61
62
63
64
65
66
67
68
69
70
71
72 func cmpstackvarlt(a, b *Node) bool {
73 if (a.Class() == PAUTO) != (b.Class() == PAUTO) {
74 return b.Class() == PAUTO
75 }
76
77 if a.Class() != PAUTO {
78 return a.Xoffset < b.Xoffset
79 }
80
81 if a.Name.Used() != b.Name.Used() {
82 return a.Name.Used()
83 }
84
85 ap := types.Haspointers(a.Type)
86 bp := types.Haspointers(b.Type)
87 if ap != bp {
88 return ap
89 }
90
91 ap = a.Name.Needzero()
92 bp = b.Name.Needzero()
93 if ap != bp {
94 return ap
95 }
96
97 if a.Type.Width != b.Type.Width {
98 return a.Type.Width > b.Type.Width
99 }
100
101 return a.Sym.Name < b.Sym.Name
102 }
103
104
105 type byStackVar []*Node
106
107 func (s byStackVar) Len() int { return len(s) }
108 func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
109 func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
110
111 func (s *ssafn) AllocFrame(f *ssa.Func) {
112 s.stksize = 0
113 s.stkptrsize = 0
114 fn := s.curfn.Func
115
116
117 for _, ln := range fn.Dcl {
118 if ln.Class() == PAUTO {
119 ln.Name.SetUsed(false)
120 }
121 }
122
123 for _, l := range f.RegAlloc {
124 if ls, ok := l.(ssa.LocalSlot); ok {
125 ls.N.(*Node).Name.SetUsed(true)
126 }
127 }
128
129 scratchUsed := false
130 for _, b := range f.Blocks {
131 for _, v := range b.Values {
132 if n, ok := v.Aux.(*Node); ok {
133 switch n.Class() {
134 case PPARAM, PPARAMOUT:
135
136 if n != nodfp {
137 n.Name.SetUsed(true)
138 }
139 case PAUTO:
140 n.Name.SetUsed(true)
141 }
142 }
143 if !scratchUsed {
144 scratchUsed = v.Op.UsesScratch()
145 }
146
147 }
148 }
149
150 if f.Config.NeedsFpScratch && scratchUsed {
151 s.scratchFpMem = tempAt(src.NoXPos, s.curfn, types.Types[TUINT64])
152 }
153
154 sort.Sort(byStackVar(fn.Dcl))
155
156
157 lastHasPtr := false
158 for i, n := range fn.Dcl {
159 if n.Op != ONAME || n.Class() != PAUTO {
160 continue
161 }
162 if !n.Name.Used() {
163 fn.Dcl = fn.Dcl[:i]
164 break
165 }
166
167 dowidth(n.Type)
168 w := n.Type.Width
169 if w >= thearch.MAXWIDTH || w < 0 {
170 Fatalf("bad width")
171 }
172 if w == 0 && lastHasPtr {
173
174
175
176
177 w = 1
178 }
179 s.stksize += w
180 s.stksize = Rnd(s.stksize, int64(n.Type.Align))
181 if types.Haspointers(n.Type) {
182 s.stkptrsize = s.stksize
183 lastHasPtr = true
184 } else {
185 lastHasPtr = false
186 }
187 if thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
188 s.stksize = Rnd(s.stksize, int64(Widthptr))
189 }
190 n.Xoffset = -s.stksize
191 }
192
193 s.stksize = Rnd(s.stksize, int64(Widthreg))
194 s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg))
195 }
196
197 func funccompile(fn *Node) {
198 if Curfn != nil {
199 Fatalf("funccompile %v inside %v", fn.Func.Nname.Sym, Curfn.Func.Nname.Sym)
200 }
201
202 if fn.Type == nil {
203 if nerrors == 0 {
204 Fatalf("funccompile missing type")
205 }
206 return
207 }
208
209
210 dowidth(fn.Type)
211
212 if fn.Nbody.Len() == 0 {
213
214 fn.Func.initLSym(false)
215 emitptrargsmap(fn)
216 return
217 }
218
219 dclcontext = PAUTO
220 Curfn = fn
221
222 compile(fn)
223
224 Curfn = nil
225 dclcontext = PEXTERN
226 }
227
228 func compile(fn *Node) {
229 saveerrors()
230
231 order(fn)
232 if nerrors != 0 {
233 return
234 }
235
236 walk(fn)
237 if nerrors != 0 {
238 return
239 }
240 if instrumenting {
241 instrument(fn)
242 }
243
244
245 Curfn = nil
246
247 if fn.funcname() == "_" {
248
249
250
251
252 return
253 }
254
255
256 fn.Func.initLSym(true)
257
258
259
260
261
262 for _, n := range fn.Func.Dcl {
263 switch n.Class() {
264 case PPARAM, PPARAMOUT, PAUTO:
265 if livenessShouldTrack(n) && n.Addrtaken() {
266 dtypesym(n.Type)
267
268
269 if fn.Func.lsym.Func.StackObjects == nil {
270 fn.Func.lsym.Func.StackObjects = Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj")
271 }
272 }
273 }
274 }
275
276 if compilenow() {
277 compileSSA(fn, 0)
278 } else {
279 compilequeue = append(compilequeue, fn)
280 }
281 }
282
283
284
285
286
287 func compilenow() bool {
288 return nBackendWorkers == 1 && Debug_compilelater == 0
289 }
290
291 const maxStackSize = 1 << 30
292
293
294
295
296
297 func compileSSA(fn *Node, worker int) {
298 f := buildssa(fn, worker)
299
300 if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type.ArgWidth() >= maxStackSize {
301 largeStackFramesMu.Lock()
302 largeStackFrames = append(largeStackFrames, largeStack{locals: f.Frontend().(*ssafn).stksize, args: fn.Type.ArgWidth(), pos: fn.Pos})
303 largeStackFramesMu.Unlock()
304 return
305 }
306 pp := newProgs(fn, worker)
307 defer pp.Free()
308 genssa(f, pp)
309
310
311
312
313
314
315 if pp.Text.To.Offset >= maxStackSize {
316 largeStackFramesMu.Lock()
317 locals := f.Frontend().(*ssafn).stksize
318 largeStackFrames = append(largeStackFrames, largeStack{locals: locals, args: fn.Type.ArgWidth(), callee: pp.Text.To.Offset - locals, pos: fn.Pos})
319 largeStackFramesMu.Unlock()
320 return
321 }
322
323 pp.Flush()
324
325 fieldtrack(pp.Text.From.Sym, fn.Func.FieldTrack)
326 }
327
328 func init() {
329 if race.Enabled {
330 rand.Seed(time.Now().UnixNano())
331 }
332 }
333
334
335
336
337 func compileFunctions() {
338 if len(compilequeue) != 0 {
339 sizeCalculationDisabled = true
340 if race.Enabled {
341
342 tmp := make([]*Node, len(compilequeue))
343 perm := rand.Perm(len(compilequeue))
344 for i, v := range perm {
345 tmp[v] = compilequeue[i]
346 }
347 copy(compilequeue, tmp)
348 } else {
349
350
351
352 sort.Slice(compilequeue, func(i, j int) bool {
353 return compilequeue[i].Nbody.Len() > compilequeue[j].Nbody.Len()
354 })
355 }
356 var wg sync.WaitGroup
357 Ctxt.InParallel = true
358 c := make(chan *Node, nBackendWorkers)
359 for i := 0; i < nBackendWorkers; i++ {
360 wg.Add(1)
361 go func(worker int) {
362 for fn := range c {
363 compileSSA(fn, worker)
364 }
365 wg.Done()
366 }(i)
367 }
368 for _, fn := range compilequeue {
369 c <- fn
370 }
371 close(c)
372 compilequeue = nil
373 wg.Wait()
374 Ctxt.InParallel = false
375 sizeCalculationDisabled = false
376 }
377 }
378
379 func debuginfo(fnsym *obj.LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) {
380 fn := curfn.(*Node)
381 if fn.Func.Nname != nil {
382 if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect {
383 Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
384 }
385 }
386
387 var automDecls []*Node
388
389 for _, n := range fn.Func.Dcl {
390 if n.Op != ONAME {
391 continue
392 }
393 var name obj.AddrName
394 switch n.Class() {
395 case PAUTO:
396 if !n.Name.Used() {
397
398 if fnsym.Func.Text != nil {
399 Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
400 }
401 continue
402 }
403 name = obj.NAME_AUTO
404 case PPARAM, PPARAMOUT:
405 name = obj.NAME_PARAM
406 default:
407 continue
408 }
409 automDecls = append(automDecls, n)
410 gotype := ngotype(n).Linksym()
411 fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{
412 Asym: Ctxt.Lookup(n.Sym.Name),
413 Aoffset: int32(n.Xoffset),
414 Name: name,
415 Gotype: gotype,
416 })
417 }
418
419 decls, dwarfVars := createDwarfVars(fnsym, fn.Func, automDecls)
420
421 var varScopes []ScopeID
422 for _, decl := range decls {
423 pos := decl.Pos
424 if decl.Name.Defn != nil && (decl.Name.Captured() || decl.Name.Byval()) {
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439 pos = decl.Name.Defn.Pos
440 }
441 varScopes = append(varScopes, findScope(fn.Func.Marks, pos))
442 }
443
444 scopes := assembleScopes(fnsym, fn, dwarfVars, varScopes)
445 var inlcalls dwarf.InlCalls
446 if genDwarfInline > 0 {
447 inlcalls = assembleInlines(fnsym, dwarfVars)
448 }
449 return scopes, inlcalls
450 }
451
452
453
454 func createSimpleVars(automDecls []*Node) ([]*Node, []*dwarf.Var, map[*Node]bool) {
455 var vars []*dwarf.Var
456 var decls []*Node
457 selected := make(map[*Node]bool)
458 for _, n := range automDecls {
459 if n.IsAutoTmp() {
460 continue
461 }
462
463 decls = append(decls, n)
464 vars = append(vars, createSimpleVar(n))
465 selected[n] = true
466 }
467 return decls, vars, selected
468 }
469
470 func createSimpleVar(n *Node) *dwarf.Var {
471 var abbrev int
472 offs := n.Xoffset
473
474 switch n.Class() {
475 case PAUTO:
476 abbrev = dwarf.DW_ABRV_AUTO
477 if Ctxt.FixedFrameSize() == 0 {
478 offs -= int64(Widthptr)
479 }
480 if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) || objabi.GOARCH == "arm64" {
481
482 offs -= int64(Widthptr)
483 }
484
485 case PPARAM, PPARAMOUT:
486 abbrev = dwarf.DW_ABRV_PARAM
487 offs += Ctxt.FixedFrameSize()
488 default:
489 Fatalf("createSimpleVar unexpected class %v for node %v", n.Class(), n)
490 }
491
492 typename := dwarf.InfoPrefix + typesymname(n.Type)
493 inlIndex := 0
494 if genDwarfInline > 1 {
495 if n.InlFormal() || n.InlLocal() {
496 inlIndex = posInlIndex(n.Pos) + 1
497 if n.InlFormal() {
498 abbrev = dwarf.DW_ABRV_PARAM
499 }
500 }
501 }
502 declpos := Ctxt.InnermostPos(n.Pos)
503 return &dwarf.Var{
504 Name: n.Sym.Name,
505 IsReturnValue: n.Class() == PPARAMOUT,
506 IsInlFormal: n.InlFormal(),
507 Abbrev: abbrev,
508 StackOffset: int32(offs),
509 Type: Ctxt.Lookup(typename),
510 DeclFile: declpos.RelFilename(),
511 DeclLine: declpos.RelLine(),
512 DeclCol: declpos.Col(),
513 InlIndex: int32(inlIndex),
514 ChildIndex: -1,
515 }
516 }
517
518
519
520 func createComplexVars(fn *Func) ([]*Node, []*dwarf.Var, map[*Node]bool) {
521 debugInfo := fn.DebugInfo
522
523
524 var decls []*Node
525 var vars []*dwarf.Var
526 ssaVars := make(map[*Node]bool)
527
528 for varID, dvar := range debugInfo.Vars {
529 n := dvar.(*Node)
530 ssaVars[n] = true
531 for _, slot := range debugInfo.VarSlots[varID] {
532 ssaVars[debugInfo.Slots[slot].N.(*Node)] = true
533 }
534
535 if dvar := createComplexVar(fn, ssa.VarID(varID)); dvar != nil {
536 decls = append(decls, n)
537 vars = append(vars, dvar)
538 }
539 }
540
541 return decls, vars, ssaVars
542 }
543
544
545
546 func createDwarfVars(fnsym *obj.LSym, fn *Func, automDecls []*Node) ([]*Node, []*dwarf.Var) {
547
548 var vars []*dwarf.Var
549 var decls []*Node
550 var selected map[*Node]bool
551 if Ctxt.Flag_locationlists && Ctxt.Flag_optimize && fn.DebugInfo != nil {
552 decls, vars, selected = createComplexVars(fn)
553 } else {
554 decls, vars, selected = createSimpleVars(automDecls)
555 }
556
557 dcl := automDecls
558 if fnsym.WasInlined() {
559 dcl = preInliningDcls(fnsym)
560 }
561
562
563
564
565
566
567
568
569
570
571
572
573
574 for _, n := range dcl {
575 if _, found := selected[n]; found {
576 continue
577 }
578 c := n.Sym.Name[0]
579 if c == '.' || n.Type.IsUntyped() {
580 continue
581 }
582 if n.Class() == PPARAM && !canSSAType(n.Type) {
583
584
585
586
587
588
589
590 vars = append(vars, createSimpleVar(n))
591 decls = append(decls, n)
592 continue
593 }
594 typename := dwarf.InfoPrefix + typesymname(n.Type)
595 decls = append(decls, n)
596 abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
597 isReturnValue := (n.Class() == PPARAMOUT)
598 if n.Class() == PPARAM || n.Class() == PPARAMOUT {
599 abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
600 } else if n.Class() == PAUTOHEAP {
601
602
603
604
605
606
607
608 stackcopy := n.Name.Param.Stackcopy
609 if stackcopy != nil && (stackcopy.Class() == PPARAM || stackcopy.Class() == PPARAMOUT) {
610 abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
611 isReturnValue = (stackcopy.Class() == PPARAMOUT)
612 }
613 }
614 inlIndex := 0
615 if genDwarfInline > 1 {
616 if n.InlFormal() || n.InlLocal() {
617 inlIndex = posInlIndex(n.Pos) + 1
618 if n.InlFormal() {
619 abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
620 }
621 }
622 }
623 declpos := Ctxt.InnermostPos(n.Pos)
624 vars = append(vars, &dwarf.Var{
625 Name: n.Sym.Name,
626 IsReturnValue: isReturnValue,
627 Abbrev: abbrev,
628 StackOffset: int32(n.Xoffset),
629 Type: Ctxt.Lookup(typename),
630 DeclFile: declpos.RelFilename(),
631 DeclLine: declpos.RelLine(),
632 DeclCol: declpos.Col(),
633 InlIndex: int32(inlIndex),
634 ChildIndex: -1,
635 })
636
637
638
639 gotype := ngotype(n).Linksym()
640 fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{
641 Asym: Ctxt.Lookup(n.Sym.Name),
642 Aoffset: int32(-1),
643 Name: obj.NAME_DELETED_AUTO,
644 Gotype: gotype,
645 })
646
647 }
648
649 return decls, vars
650 }
651
652
653
654
655
656
657
658 func preInliningDcls(fnsym *obj.LSym) []*Node {
659 fn := Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*Node)
660 var rdcl []*Node
661 for _, n := range fn.Func.Inl.Dcl {
662 c := n.Sym.Name[0]
663
664
665 if unversion(n.Sym.Name) == "_" || c == '.' || n.Type.IsUntyped() {
666 continue
667 }
668 rdcl = append(rdcl, n)
669 }
670 return rdcl
671 }
672
673
674
675
676 func stackOffset(slot ssa.LocalSlot) int32 {
677 n := slot.N.(*Node)
678 var base int64
679 switch n.Class() {
680 case PAUTO:
681 if Ctxt.FixedFrameSize() == 0 {
682 base -= int64(Widthptr)
683 }
684 if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) || objabi.GOARCH == "arm64" {
685
686 base -= int64(Widthptr)
687 }
688 case PPARAM, PPARAMOUT:
689 base += Ctxt.FixedFrameSize()
690 }
691 return int32(base + n.Xoffset + slot.Off)
692 }
693
694
695 func createComplexVar(fn *Func, varID ssa.VarID) *dwarf.Var {
696 debug := fn.DebugInfo
697 n := debug.Vars[varID].(*Node)
698
699 var abbrev int
700 switch n.Class() {
701 case PAUTO:
702 abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
703 case PPARAM, PPARAMOUT:
704 abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
705 default:
706 return nil
707 }
708
709 gotype := ngotype(n).Linksym()
710 typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
711 inlIndex := 0
712 if genDwarfInline > 1 {
713 if n.InlFormal() || n.InlLocal() {
714 inlIndex = posInlIndex(n.Pos) + 1
715 if n.InlFormal() {
716 abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
717 }
718 }
719 }
720 declpos := Ctxt.InnermostPos(n.Pos)
721 dvar := &dwarf.Var{
722 Name: n.Sym.Name,
723 IsReturnValue: n.Class() == PPARAMOUT,
724 IsInlFormal: n.InlFormal(),
725 Abbrev: abbrev,
726 Type: Ctxt.Lookup(typename),
727
728
729
730
731 StackOffset: stackOffset(debug.Slots[debug.VarSlots[varID][0]]),
732 DeclFile: declpos.RelFilename(),
733 DeclLine: declpos.RelLine(),
734 DeclCol: declpos.Col(),
735 InlIndex: int32(inlIndex),
736 ChildIndex: -1,
737 }
738 list := debug.LocationLists[varID]
739 if len(list) != 0 {
740 dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
741 debug.PutLocationList(list, Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
742 }
743 }
744 return dvar
745 }
746
747
748
749 func fieldtrack(fnsym *obj.LSym, tracked map[*types.Sym]struct{}) {
750 if fnsym == nil {
751 return
752 }
753 if objabi.Fieldtrack_enabled == 0 || len(tracked) == 0 {
754 return
755 }
756
757 trackSyms := make([]*types.Sym, 0, len(tracked))
758 for sym := range tracked {
759 trackSyms = append(trackSyms, sym)
760 }
761 sort.Sort(symByName(trackSyms))
762 for _, sym := range trackSyms {
763 r := obj.Addrel(fnsym)
764 r.Sym = sym.Linksym()
765 r.Type = objabi.R_USEFIELD
766 }
767 }
768
769 type symByName []*types.Sym
770
771 func (a symByName) Len() int { return len(a) }
772 func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
773 func (a symByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
774
View as plain text