Source file src/pkg/cmd/compile/internal/gc/inl.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gc
28
29 import (
30 "cmd/compile/internal/types"
31 "cmd/internal/obj"
32 "cmd/internal/src"
33 "fmt"
34 "strings"
35 )
36
37
38 const (
39 inlineMaxBudget = 80
40 inlineExtraAppendCost = 0
41
42 inlineExtraCallCost = 57
43 inlineExtraPanicCost = 1
44 inlineExtraThrowCost = inlineMaxBudget
45
46 inlineBigFunctionNodes = 5000
47 inlineBigFunctionMaxCost = 20
48 )
49
50
51
52 func fnpkg(fn *Node) *types.Pkg {
53 if fn.IsMethod() {
54
55 rcvr := fn.Type.Recv().Type
56
57 if rcvr.IsPtr() {
58 rcvr = rcvr.Elem()
59 }
60 if rcvr.Sym == nil {
61 Fatalf("receiver with no sym: [%v] %L (%v)", fn.Sym, fn, rcvr)
62 }
63 return rcvr.Sym.Pkg
64 }
65
66
67 return fn.Sym.Pkg
68 }
69
70
71
72 func typecheckinl(fn *Node) {
73 lno := setlineno(fn)
74
75 expandInline(fn)
76
77
78
79
80
81 pkg := fnpkg(fn)
82
83 if pkg == localpkg || pkg == nil {
84 return
85 }
86
87 if Debug['m'] > 2 || Debug_export != 0 {
88 fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, asNodes(fn.Func.Inl.Body))
89 }
90
91 savefn := Curfn
92 Curfn = fn
93 typecheckslice(fn.Func.Inl.Body, ctxStmt)
94 Curfn = savefn
95
96
97
98
99
100 fn.Func.Inl.Dcl = append(fn.Func.Inl.Dcl, fn.Func.Dcl...)
101 fn.Func.Dcl = nil
102
103 lineno = lno
104 }
105
106
107
108
109 func caninl(fn *Node) {
110 if fn.Op != ODCLFUNC {
111 Fatalf("caninl %v", fn)
112 }
113 if fn.Func.Nname == nil {
114 Fatalf("caninl no nname %+v", fn)
115 }
116
117 var reason string
118 if Debug['m'] > 1 {
119 defer func() {
120 if reason != "" {
121 fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
122 }
123 }()
124 }
125
126
127 if fn.Func.Pragma&Noinline != 0 {
128 reason = "marked go:noinline"
129 return
130 }
131
132
133 if flag_race && fn.Func.Pragma&Norace != 0 {
134 reason = "marked go:norace with -race compilation"
135 return
136 }
137
138
139
140 if fn.Func.Pragma&CgoUnsafeArgs != 0 {
141 reason = "marked go:cgo_unsafe_args"
142 return
143 }
144
145
146
147 if fn.Func.Pragma&UintptrEscapes != 0 {
148 reason = "marked as having an escaping uintptr argument"
149 return
150 }
151
152
153
154
155
156 if fn.Func.Pragma&Yeswritebarrierrec != 0 {
157 reason = "marked go:yeswritebarrierrec"
158 return
159 }
160
161
162 if fn.Nbody.Len() == 0 {
163 reason = "no function body"
164 return
165 }
166
167 if fn.Typecheck() == 0 {
168 Fatalf("caninl on non-typechecked function %v", fn)
169 }
170
171 n := fn.Func.Nname
172 if n.Func.InlinabilityChecked() {
173 return
174 }
175 defer n.Func.SetInlinabilityChecked(true)
176
177 cc := int32(inlineExtraCallCost)
178 if Debug['l'] == 4 {
179 cc = 1
180 }
181
182
183
184
185
186
187
188
189
190
191 visitor := hairyVisitor{
192 budget: inlineMaxBudget,
193 extraCallCost: cc,
194 usedLocals: make(map[*Node]bool),
195 }
196 if visitor.visitList(fn.Nbody) {
197 reason = visitor.reason
198 return
199 }
200 if visitor.budget < 0 {
201 reason = fmt.Sprintf("function too complex: cost %d exceeds budget %d", inlineMaxBudget-visitor.budget, inlineMaxBudget)
202 return
203 }
204
205 n.Func.Inl = &Inline{
206 Cost: inlineMaxBudget - visitor.budget,
207 Dcl: inlcopylist(pruneUnusedAutos(n.Name.Defn.Func.Dcl, &visitor)),
208 Body: inlcopylist(fn.Nbody.Slice()),
209 }
210
211
212
213 fn.Type.FuncType().Nname = asTypesNode(n)
214
215 if Debug['m'] > 1 {
216 fmt.Printf("%v: can inline %#v as: %#v { %#v }\n", fn.Line(), n, fn.Type, asNodes(n.Func.Inl.Body))
217 } else if Debug['m'] != 0 {
218 fmt.Printf("%v: can inline %v\n", fn.Line(), n)
219 }
220 }
221
222
223
224 func inlFlood(n *Node) {
225 if n == nil {
226 return
227 }
228 if n.Op != ONAME || n.Class() != PFUNC {
229 Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op, n.Class())
230 }
231 if n.Func == nil {
232 Fatalf("inlFlood: missing Func on %v", n)
233 }
234 if n.Func.Inl == nil {
235 return
236 }
237
238 if n.Func.ExportInline() {
239 return
240 }
241 n.Func.SetExportInline(true)
242
243 typecheckinl(n)
244
245 inspectList(asNodes(n.Func.Inl.Body), func(n *Node) bool {
246 switch n.Op {
247 case ONAME:
248
249
250
251
252 if n.Class() == PEXTERN || n.Class() == PFUNC && !n.isMethodExpression() {
253 exportsym(n)
254 }
255
256 case OCALLFUNC, OCALLMETH:
257
258
259 inlFlood(asNode(n.Left.Type.Nname()))
260 }
261 return true
262 })
263 }
264
265
266
267 type hairyVisitor struct {
268 budget int32
269 reason string
270 extraCallCost int32
271 usedLocals map[*Node]bool
272 }
273
274
275 func (v *hairyVisitor) visitList(ll Nodes) bool {
276 for _, n := range ll.Slice() {
277 if v.visit(n) {
278 return true
279 }
280 }
281 return false
282 }
283
284 func (v *hairyVisitor) visit(n *Node) bool {
285 if n == nil {
286 return false
287 }
288
289 switch n.Op {
290
291 case OCALLFUNC:
292
293
294
295
296 if n.Left.Op == ONAME && n.Left.Class() == PFUNC && isRuntimePkg(n.Left.Sym.Pkg) {
297 fn := n.Left.Sym.Name
298 if fn == "getcallerpc" || fn == "getcallersp" {
299 v.reason = "call to " + fn
300 return true
301 }
302 if fn == "throw" {
303 v.budget -= inlineExtraThrowCost
304 break
305 }
306 }
307
308 if isIntrinsicCall(n) {
309 v.budget--
310 break
311 }
312
313 if fn := n.Left.Func; fn != nil && fn.Inl != nil {
314 v.budget -= fn.Inl.Cost
315 break
316 }
317 if n.Left.isMethodExpression() {
318 if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl != nil {
319 v.budget -= d.Func.Inl.Cost
320 break
321 }
322 }
323
324
325
326
327 v.budget -= v.extraCallCost
328
329
330 case OCALLMETH:
331 t := n.Left.Type
332 if t == nil {
333 Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
334 }
335 if t.Nname() == nil {
336 Fatalf("no function definition for [%p] %+v\n", t, t)
337 }
338 if isRuntimePkg(n.Left.Sym.Pkg) {
339 fn := n.Left.Sym.Name
340 if fn == "heapBits.nextArena" {
341
342
343
344
345
346 break
347 }
348 }
349 if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl != nil {
350 v.budget -= inlfn.Inl.Cost
351 break
352 }
353
354 v.budget -= v.extraCallCost
355
356
357 case OCALL, OCALLINTER:
358
359 v.budget -= v.extraCallCost
360
361 case OPANIC:
362 v.budget -= inlineExtraPanicCost
363
364 case ORECOVER:
365
366
367 v.reason = "call to recover"
368 return true
369
370 case OCLOSURE,
371 OCALLPART,
372 ORANGE,
373 OFOR,
374 OFORUNTIL,
375 OSELECT,
376 OTYPESW,
377 OGO,
378 ODEFER,
379 ODCLTYPE,
380 OBREAK,
381 ORETJMP:
382 v.reason = "unhandled op " + n.Op.String()
383 return true
384
385 case OAPPEND:
386 v.budget -= inlineExtraAppendCost
387
388 case ODCLCONST, OEMPTY, OFALL, OLABEL:
389
390 return false
391
392 case OIF:
393 if Isconst(n.Left, CTBOOL) {
394
395 return v.visitList(n.Ninit) || v.visitList(n.Nbody) ||
396 v.visitList(n.Rlist)
397 }
398
399 case ONAME:
400 if n.Class() == PAUTO {
401 v.usedLocals[n] = true
402 }
403
404 }
405
406 v.budget--
407
408
409 if v.budget < 0 && Debug['m'] < 2 {
410 return true
411 }
412
413 return v.visit(n.Left) || v.visit(n.Right) ||
414 v.visitList(n.List) || v.visitList(n.Rlist) ||
415 v.visitList(n.Ninit) || v.visitList(n.Nbody)
416 }
417
418
419
420
421 func inlcopylist(ll []*Node) []*Node {
422 s := make([]*Node, 0, len(ll))
423 for _, n := range ll {
424 s = append(s, inlcopy(n))
425 }
426 return s
427 }
428
429 func inlcopy(n *Node) *Node {
430 if n == nil {
431 return nil
432 }
433
434 switch n.Op {
435 case ONAME, OTYPE, OLITERAL:
436 return n
437 }
438
439 m := n.copy()
440 if m.Func != nil {
441 Fatalf("unexpected Func: %v", m)
442 }
443 m.Left = inlcopy(n.Left)
444 m.Right = inlcopy(n.Right)
445 m.List.Set(inlcopylist(n.List.Slice()))
446 m.Rlist.Set(inlcopylist(n.Rlist.Slice()))
447 m.Ninit.Set(inlcopylist(n.Ninit.Slice()))
448 m.Nbody.Set(inlcopylist(n.Nbody.Slice()))
449
450 return m
451 }
452
453 func countNodes(n *Node) int {
454 if n == nil {
455 return 0
456 }
457 cnt := 1
458 cnt += countNodes(n.Left)
459 cnt += countNodes(n.Right)
460 for _, n1 := range n.Ninit.Slice() {
461 cnt += countNodes(n1)
462 }
463 for _, n1 := range n.Nbody.Slice() {
464 cnt += countNodes(n1)
465 }
466 for _, n1 := range n.List.Slice() {
467 cnt += countNodes(n1)
468 }
469 for _, n1 := range n.Rlist.Slice() {
470 cnt += countNodes(n1)
471 }
472 return cnt
473 }
474
475
476
477 func inlcalls(fn *Node) {
478 savefn := Curfn
479 Curfn = fn
480 maxCost := int32(inlineMaxBudget)
481 if countNodes(fn) >= inlineBigFunctionNodes {
482 maxCost = inlineBigFunctionMaxCost
483 }
484 fn = inlnode(fn, maxCost)
485 if fn != Curfn {
486 Fatalf("inlnode replaced curfn")
487 }
488 Curfn = savefn
489 }
490
491
492 func inlconv2stmt(n *Node) {
493 n.Op = OBLOCK
494
495
496 n.List.Set(n.Nbody.Slice())
497
498 n.Nbody.Set(nil)
499 n.Rlist.Set(nil)
500 }
501
502
503
504
505 func inlconv2expr(n *Node) *Node {
506 r := n.Rlist.First()
507 return addinit(r, append(n.Ninit.Slice(), n.Nbody.Slice()...))
508 }
509
510
511
512
513
514
515 func inlconv2list(n *Node) []*Node {
516 if n.Op != OINLCALL || n.Rlist.Len() == 0 {
517 Fatalf("inlconv2list %+v\n", n)
518 }
519
520 s := n.Rlist.Slice()
521 s[0] = addinit(s[0], append(n.Ninit.Slice(), n.Nbody.Slice()...))
522 return s
523 }
524
525 func inlnodelist(l Nodes, maxCost int32) {
526 s := l.Slice()
527 for i := range s {
528 s[i] = inlnode(s[i], maxCost)
529 }
530 }
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545 func inlnode(n *Node, maxCost int32) *Node {
546 if n == nil {
547 return n
548 }
549
550 switch n.Op {
551
552 case ODEFER, OGO:
553 switch n.Left.Op {
554 case OCALLFUNC, OCALLMETH:
555 n.Left.SetNoInline(true)
556 }
557 return n
558
559
560
561 case OCLOSURE:
562 return n
563 }
564
565 lno := setlineno(n)
566
567 inlnodelist(n.Ninit, maxCost)
568 for _, n1 := range n.Ninit.Slice() {
569 if n1.Op == OINLCALL {
570 inlconv2stmt(n1)
571 }
572 }
573
574 n.Left = inlnode(n.Left, maxCost)
575 if n.Left != nil && n.Left.Op == OINLCALL {
576 n.Left = inlconv2expr(n.Left)
577 }
578
579 n.Right = inlnode(n.Right, maxCost)
580 if n.Right != nil && n.Right.Op == OINLCALL {
581 if n.Op == OFOR || n.Op == OFORUNTIL {
582 inlconv2stmt(n.Right)
583 } else {
584 n.Right = inlconv2expr(n.Right)
585 }
586 }
587
588 inlnodelist(n.List, maxCost)
589 if n.Op == OBLOCK {
590 for _, n2 := range n.List.Slice() {
591 if n2.Op == OINLCALL {
592 inlconv2stmt(n2)
593 }
594 }
595 } else {
596 s := n.List.Slice()
597 for i1, n1 := range s {
598 if n1 != nil && n1.Op == OINLCALL {
599 s[i1] = inlconv2expr(s[i1])
600 }
601 }
602 }
603
604 inlnodelist(n.Rlist, maxCost)
605 if n.Op == OAS2FUNC && n.Rlist.First().Op == OINLCALL {
606 n.Rlist.Set(inlconv2list(n.Rlist.First()))
607 n.Op = OAS2
608 n.SetTypecheck(0)
609 n = typecheck(n, ctxStmt)
610 } else {
611 s := n.Rlist.Slice()
612 for i1, n1 := range s {
613 if n1.Op == OINLCALL {
614 if n.Op == OIF {
615 inlconv2stmt(n1)
616 } else {
617 s[i1] = inlconv2expr(s[i1])
618 }
619 }
620 }
621 }
622
623 inlnodelist(n.Nbody, maxCost)
624 for _, n := range n.Nbody.Slice() {
625 if n.Op == OINLCALL {
626 inlconv2stmt(n)
627 }
628 }
629
630
631
632
633 switch n.Op {
634 case OCALLFUNC, OCALLMETH:
635 if n.NoInline() {
636 return n
637 }
638 }
639
640 switch n.Op {
641 case OCALLFUNC:
642 if Debug['m'] > 3 {
643 fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
644 }
645 if n.Left.Func != nil && n.Left.Func.Inl != nil && !isIntrinsicCall(n) {
646 n = mkinlcall(n, n.Left, maxCost)
647 } else if n.Left.isMethodExpression() && asNode(n.Left.Sym.Def) != nil {
648 n = mkinlcall(n, asNode(n.Left.Sym.Def), maxCost)
649 } else if n.Left.Op == OCLOSURE {
650 if f := inlinableClosure(n.Left); f != nil {
651 n = mkinlcall(n, f, maxCost)
652 }
653 } else if n.Left.Op == ONAME && n.Left.Name != nil && n.Left.Name.Defn != nil {
654 if d := n.Left.Name.Defn; d.Op == OAS && d.Right.Op == OCLOSURE {
655 if f := inlinableClosure(d.Right); f != nil {
656
657
658
659 if d.Left.Addrtaken() {
660 if Debug['m'] > 1 {
661 fmt.Printf("%v: cannot inline escaping closure variable %v\n", n.Line(), n.Left)
662 }
663 break
664 }
665
666
667 if unsafe, a := reassigned(n.Left); unsafe {
668 if Debug['m'] > 1 {
669 if a != nil {
670 fmt.Printf("%v: cannot inline re-assigned closure variable at %v: %v\n", n.Line(), a.Line(), a)
671 } else {
672 fmt.Printf("%v: cannot inline global closure variable %v\n", n.Line(), n.Left)
673 }
674 }
675 break
676 }
677 n = mkinlcall(n, f, maxCost)
678 }
679 }
680 }
681
682 case OCALLMETH:
683 if Debug['m'] > 3 {
684 fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right)
685 }
686
687
688 if n.Left.Type == nil {
689 Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
690 }
691
692 if n.Left.Type.Nname() == nil {
693 Fatalf("no function definition for [%p] %+v\n", n.Left.Type, n.Left.Type)
694 }
695
696 n = mkinlcall(n, asNode(n.Left.Type.FuncType().Nname), maxCost)
697 }
698
699 lineno = lno
700 return n
701 }
702
703
704
705 func inlinableClosure(n *Node) *Node {
706 c := n.Func.Closure
707 caninl(c)
708 f := c.Func.Nname
709 if f == nil || f.Func.Inl == nil {
710 return nil
711 }
712 return f
713 }
714
715
716
717
718
719
720
721 func reassigned(n *Node) (bool, *Node) {
722 if n.Op != ONAME {
723 Fatalf("reassigned %v", n)
724 }
725
726 if n.Name.Curfn == nil {
727 return true, nil
728 }
729 f := n.Name.Curfn
730
731
732
733
734
735 if f.Op == OCLOSURE {
736 f = f.Func.Closure
737 }
738 v := reassignVisitor{name: n}
739 a := v.visitList(f.Nbody)
740 return a != nil, a
741 }
742
743 type reassignVisitor struct {
744 name *Node
745 }
746
747 func (v *reassignVisitor) visit(n *Node) *Node {
748 if n == nil {
749 return nil
750 }
751 switch n.Op {
752 case OAS:
753 if n.Left == v.name && n != v.name.Name.Defn {
754 return n
755 }
756 return nil
757 case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE:
758 for _, p := range n.List.Slice() {
759 if p == v.name && n != v.name.Name.Defn {
760 return n
761 }
762 }
763 return nil
764 }
765 if a := v.visit(n.Left); a != nil {
766 return a
767 }
768 if a := v.visit(n.Right); a != nil {
769 return a
770 }
771 if a := v.visitList(n.List); a != nil {
772 return a
773 }
774 if a := v.visitList(n.Rlist); a != nil {
775 return a
776 }
777 if a := v.visitList(n.Ninit); a != nil {
778 return a
779 }
780 if a := v.visitList(n.Nbody); a != nil {
781 return a
782 }
783 return nil
784 }
785
786 func (v *reassignVisitor) visitList(l Nodes) *Node {
787 for _, n := range l.Slice() {
788 if a := v.visit(n); a != nil {
789 return a
790 }
791 }
792 return nil
793 }
794
795 func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node {
796 if n := asNode(t.Nname); n != nil && !n.isBlank() {
797 inlvar := inlvars[n]
798 if inlvar == nil {
799 Fatalf("missing inlvar for %v\n", n)
800 }
801 return inlvar
802 }
803
804 return typecheck(nblank, ctxExpr|ctxAssign)
805 }
806
807 var inlgen int
808
809
810
811
812
813
814
815
816 func mkinlcall(n, fn *Node, maxCost int32) *Node {
817 if fn.Func.Inl == nil {
818
819 return n
820 }
821 if fn.Func.Inl.Cost > maxCost {
822
823
824 return n
825 }
826
827 if fn == Curfn || fn.Name.Defn == Curfn {
828
829 return n
830 }
831
832 if instrumenting && isRuntimePkg(fn.Sym.Pkg) {
833
834
835
836
837
838
839 return n
840 }
841
842 if Debug_typecheckinl == 0 {
843 typecheckinl(fn)
844 }
845
846
847 if Debug['m'] > 1 {
848 fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, asNodes(fn.Func.Inl.Body))
849 } else if Debug['m'] != 0 {
850 fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
851 }
852 if Debug['m'] > 2 {
853 fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
854 }
855
856 if ssaDump != "" && ssaDump == Curfn.funcname() {
857 ssaDumpInlined = append(ssaDumpInlined, fn)
858 }
859
860 ninit := n.Ninit
861
862
863 inlvars := make(map[*Node]*Node)
864
865
866 var inlfvars []*Node
867
868
869 if fn.Name.Defn != nil {
870 if c := fn.Name.Defn.Func.Closure; c != nil {
871 for _, v := range c.Func.Closure.Func.Cvars.Slice() {
872 if v.Op == OXXX {
873 continue
874 }
875
876 o := v.Name.Param.Outer
877
878
879
880
881 if o == nil || (o.Name.Curfn != Curfn && o.Name.Curfn.Func.Closure != Curfn) {
882 Fatalf("%v: unresolvable capture %v %v\n", n.Line(), fn, v)
883 }
884
885 if v.Name.Byval() {
886 iv := typecheck(inlvar(v), ctxExpr)
887 ninit.Append(nod(ODCL, iv, nil))
888 ninit.Append(typecheck(nod(OAS, iv, o), ctxStmt))
889 inlvars[v] = iv
890 } else {
891 addr := newname(lookup("&" + v.Sym.Name))
892 addr.Type = types.NewPtr(v.Type)
893 ia := typecheck(inlvar(addr), ctxExpr)
894 ninit.Append(nod(ODCL, ia, nil))
895 ninit.Append(typecheck(nod(OAS, ia, nod(OADDR, o, nil)), ctxStmt))
896 inlvars[addr] = ia
897
898
899
900 inlvars[v] = typecheck(nod(ODEREF, ia, nil), ctxExpr)
901 }
902 }
903 }
904 }
905
906 for _, ln := range fn.Func.Inl.Dcl {
907 if ln.Op != ONAME {
908 continue
909 }
910 if ln.Class() == PPARAMOUT {
911 continue
912 }
913 if ln.isParamStackCopy() {
914 continue
915 }
916 inlvars[ln] = typecheck(inlvar(ln), ctxExpr)
917 if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM {
918 ninit.Append(nod(ODCL, inlvars[ln], nil))
919 }
920 if genDwarfInline > 0 {
921 inlf := inlvars[ln]
922 if ln.Class() == PPARAM {
923 inlf.SetInlFormal(true)
924 } else {
925 inlf.SetInlLocal(true)
926 }
927 inlf.Pos = ln.Pos
928 inlfvars = append(inlfvars, inlf)
929 }
930 }
931
932
933 var retvars []*Node
934 for i, t := range fn.Type.Results().Fields().Slice() {
935 var m *Node
936 mpos := t.Pos
937 if n := asNode(t.Nname); n != nil && !n.isBlank() {
938 m = inlvar(n)
939 m = typecheck(m, ctxExpr)
940 inlvars[n] = m
941 } else {
942
943 m = retvar(t, i)
944 }
945
946 if genDwarfInline > 0 {
947
948
949
950 if !strings.HasPrefix(m.Sym.Name, "~R") {
951 m.SetInlFormal(true)
952 m.Pos = mpos
953 inlfvars = append(inlfvars, m)
954 }
955 }
956
957 ninit.Append(nod(ODCL, m, nil))
958 retvars = append(retvars, m)
959 }
960
961
962 as := nod(OAS2, nil, nil)
963 as.Rlist.Set(n.List.Slice())
964
965
966
967 var vas *Node
968
969 if fn.IsMethod() {
970 rcv := fn.Type.Recv()
971
972 if n.Left.Op == ODOTMETH {
973
974
975 if n.Left.Left == nil {
976 Fatalf("method call without receiver: %+v", n)
977 }
978 ras := nod(OAS, tinlvar(rcv, inlvars), n.Left.Left)
979 ras = typecheck(ras, ctxStmt)
980 ninit.Append(ras)
981 } else {
982
983
984
985 if as.Rlist.Len() == 0 {
986 Fatalf("non-method call to method without first arg: %+v", n)
987 }
988 as.List.Append(tinlvar(rcv, inlvars))
989 }
990 }
991
992 for _, param := range fn.Type.Params().Fields().Slice() {
993
994
995
996 if !param.IsDDD() || n.IsDDD() {
997 as.List.Append(tinlvar(param, inlvars))
998 continue
999 }
1000
1001
1002
1003
1004 numvals := n.List.Len()
1005
1006 x := as.List.Len()
1007 for as.List.Len() < numvals {
1008 as.List.Append(argvar(param.Type, as.List.Len()))
1009 }
1010 varargs := as.List.Slice()[x:]
1011
1012 vas = nod(OAS, tinlvar(param, inlvars), nil)
1013 if len(varargs) == 0 {
1014 vas.Right = nodnil()
1015 vas.Right.Type = param.Type
1016 } else {
1017 vas.Right = nod(OCOMPLIT, nil, typenod(param.Type))
1018 vas.Right.List.Set(varargs)
1019 }
1020 }
1021
1022 if as.Rlist.Len() != 0 {
1023 as = typecheck(as, ctxStmt)
1024 ninit.Append(as)
1025 }
1026
1027 if vas != nil {
1028 vas = typecheck(vas, ctxStmt)
1029 ninit.Append(vas)
1030 }
1031
1032
1033 for _, n := range retvars {
1034 ras := nod(OAS, n, nil)
1035 ras = typecheck(ras, ctxStmt)
1036 ninit.Append(ras)
1037 }
1038
1039 retlabel := autolabel(".i")
1040
1041 inlgen++
1042
1043 parent := -1
1044 if b := Ctxt.PosTable.Pos(n.Pos).Base(); b != nil {
1045 parent = b.InliningIndex()
1046 }
1047 newIndex := Ctxt.InlTree.Add(parent, n.Pos, fn.Sym.Linksym())
1048
1049
1050
1051
1052
1053
1054 inlMark := nod(OINLMARK, nil, nil)
1055 inlMark.Pos = n.Pos.WithIsStmt()
1056 inlMark.Xoffset = int64(newIndex)
1057 ninit.Append(inlMark)
1058
1059 if genDwarfInline > 0 {
1060 if !fn.Sym.Linksym().WasInlined() {
1061 Ctxt.DwFixups.SetPrecursorFunc(fn.Sym.Linksym(), fn)
1062 fn.Sym.Linksym().Set(obj.AttrWasInlined, true)
1063 }
1064 }
1065
1066 subst := inlsubst{
1067 retlabel: retlabel,
1068 retvars: retvars,
1069 inlvars: inlvars,
1070 bases: make(map[*src.PosBase]*src.PosBase),
1071 newInlIndex: newIndex,
1072 }
1073
1074 body := subst.list(asNodes(fn.Func.Inl.Body))
1075
1076 lab := nodSym(OLABEL, nil, retlabel)
1077 body = append(body, lab)
1078
1079 typecheckslice(body, ctxStmt)
1080
1081 if genDwarfInline > 0 {
1082 for _, v := range inlfvars {
1083 v.Pos = subst.updatedPos(v.Pos)
1084 }
1085 }
1086
1087
1088
1089 call := nod(OINLCALL, nil, nil)
1090 call.Ninit.Set(ninit.Slice())
1091 call.Nbody.Set(body)
1092 call.Rlist.Set(retvars)
1093 call.Type = n.Type
1094 call.SetTypecheck(1)
1095
1096
1097
1098
1099
1100
1101
1102 inlnodelist(call.Nbody, maxCost)
1103 for _, n := range call.Nbody.Slice() {
1104 if n.Op == OINLCALL {
1105 inlconv2stmt(n)
1106 }
1107 }
1108
1109 if Debug['m'] > 2 {
1110 fmt.Printf("%v: After inlining %+v\n\n", call.Line(), call)
1111 }
1112
1113 return call
1114 }
1115
1116
1117
1118
1119 func inlvar(var_ *Node) *Node {
1120 if Debug['m'] > 3 {
1121 fmt.Printf("inlvar %+v\n", var_)
1122 }
1123
1124 n := newname(var_.Sym)
1125 n.Type = var_.Type
1126 n.SetClass(PAUTO)
1127 n.Name.SetUsed(true)
1128 n.Name.Curfn = Curfn
1129 n.SetAddrtaken(var_.Addrtaken())
1130
1131 Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
1132 return n
1133 }
1134
1135
1136 func retvar(t *types.Field, i int) *Node {
1137 n := newname(lookupN("~R", i))
1138 n.Type = t.Type
1139 n.SetClass(PAUTO)
1140 n.Name.SetUsed(true)
1141 n.Name.Curfn = Curfn
1142 Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
1143 return n
1144 }
1145
1146
1147
1148 func argvar(t *types.Type, i int) *Node {
1149 n := newname(lookupN("~arg", i))
1150 n.Type = t.Elem()
1151 n.SetClass(PAUTO)
1152 n.Name.SetUsed(true)
1153 n.Name.Curfn = Curfn
1154 Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
1155 return n
1156 }
1157
1158
1159
1160 type inlsubst struct {
1161
1162 retlabel *types.Sym
1163
1164
1165 retvars []*Node
1166
1167 inlvars map[*Node]*Node
1168
1169
1170
1171 bases map[*src.PosBase]*src.PosBase
1172
1173
1174
1175 newInlIndex int
1176 }
1177
1178
1179 func (subst *inlsubst) list(ll Nodes) []*Node {
1180 s := make([]*Node, 0, ll.Len())
1181 for _, n := range ll.Slice() {
1182 s = append(s, subst.node(n))
1183 }
1184 return s
1185 }
1186
1187
1188
1189
1190
1191 func (subst *inlsubst) node(n *Node) *Node {
1192 if n == nil {
1193 return nil
1194 }
1195
1196 switch n.Op {
1197 case ONAME:
1198 if inlvar := subst.inlvars[n]; inlvar != nil {
1199 if Debug['m'] > 2 {
1200 fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
1201 }
1202 return inlvar
1203 }
1204
1205 if Debug['m'] > 2 {
1206 fmt.Printf("not substituting name %+v\n", n)
1207 }
1208 return n
1209
1210 case OLITERAL, OTYPE:
1211
1212
1213
1214 if n.Sym != nil {
1215 return n
1216 }
1217
1218
1219
1220
1221 case ORETURN:
1222 m := nodSym(OGOTO, nil, subst.retlabel)
1223 m.Ninit.Set(subst.list(n.Ninit))
1224
1225 if len(subst.retvars) != 0 && n.List.Len() != 0 {
1226 as := nod(OAS2, nil, nil)
1227
1228
1229
1230
1231 for _, n := range subst.retvars {
1232 as.List.Append(n)
1233 }
1234 as.Rlist.Set(subst.list(n.List))
1235 as = typecheck(as, ctxStmt)
1236 m.Ninit.Append(as)
1237 }
1238
1239 typecheckslice(m.Ninit.Slice(), ctxStmt)
1240 m = typecheck(m, ctxStmt)
1241
1242
1243 return m
1244
1245 case OGOTO, OLABEL:
1246 m := n.copy()
1247 m.Pos = subst.updatedPos(m.Pos)
1248 m.Ninit.Set(nil)
1249 p := fmt.Sprintf("%s·%d", n.Sym.Name, inlgen)
1250 m.Sym = lookup(p)
1251
1252 return m
1253 }
1254
1255 m := n.copy()
1256 m.Pos = subst.updatedPos(m.Pos)
1257 m.Ninit.Set(nil)
1258
1259 if n.Op == OCLOSURE {
1260 Fatalf("cannot inline function containing closure: %+v", n)
1261 }
1262
1263 m.Left = subst.node(n.Left)
1264 m.Right = subst.node(n.Right)
1265 m.List.Set(subst.list(n.List))
1266 m.Rlist.Set(subst.list(n.Rlist))
1267 m.Ninit.Set(append(m.Ninit.Slice(), subst.list(n.Ninit)...))
1268 m.Nbody.Set(subst.list(n.Nbody))
1269
1270 return m
1271 }
1272
1273 func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
1274 pos := Ctxt.PosTable.Pos(xpos)
1275 oldbase := pos.Base()
1276 newbase := subst.bases[oldbase]
1277 if newbase == nil {
1278 newbase = src.NewInliningBase(oldbase, subst.newInlIndex)
1279 subst.bases[oldbase] = newbase
1280 }
1281 pos.SetBase(newbase)
1282 return Ctxt.PosTable.XPos(pos)
1283 }
1284
1285 func pruneUnusedAutos(ll []*Node, vis *hairyVisitor) []*Node {
1286 s := make([]*Node, 0, len(ll))
1287 for _, n := range ll {
1288 if n.Class() == PAUTO {
1289 if _, found := vis.usedLocals[n]; !found {
1290 continue
1291 }
1292 }
1293 s = append(s, n)
1294 }
1295 return s
1296 }
1297
View as plain text