./shuang.go:17:6: cannot inline main: function too complex: cost 90 exceeds budget 80 /var/folders/9z/kzqrt95n3wj9fq3189s2vvh80000gn/T/go-build416805477/b001/_gomod_.go:6:8: can inline init.0 as: func() { __debug_modinfo__ = "0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tdashen\nmod\tdashen\t(devel)\t\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\xd8\xf2" } ./shuang.go:5:11:[1] add esc: a ./shuang.go:5:11:[1] add esc: b ./shuang.go:5:11:[1] add esc: a + b ./shuang.go:5:2:[1] add esc: return a + b ./shuang.go:5:2:[1] add escassign: ~r2( a(true) g(1) l(3) x(16) class(PPARAMOUT))[NAME] = a + b( l(5) tc(1))[+] ./shuang.go:5:11:[1] add escassign: ~r2( a(true) g(1) l(3) x(16) class(PPARAMOUT))[NAME] = a( a(true) g(2) l(3) x(0) class(PPARAM) ld(1) tc(1) used)[NAME] ./shuang.go:5:11:[1] add escassign: ~r2( a(true) g(1) l(3) x(16) class(PPARAMOUT))[NAME] = b( a(true) g(3) l(3) x(8) class(PPARAM) ld(1) tc(1) used)[NAME] ./shuang.go:10:2:[1] iter esc: res ./shuang.go:10:2:[1] iter esc: var res int ./shuang.go:10:6:[1] iter esc: res ./shuang.go:10:9:[1] iter esc: 1 ./shuang.go:10:6:[1] iter esc: res := 1 ./shuang.go:10:6:[1] iter escassign: res( a(true) g(3) l(10) x(0) class(PAUTO) ld(1) tc(1) assigned used)[NAME] = 1( l(10) tc(1))[LITERAL] ./shuang.go:11:6:[1] iter esc: i ./shuang.go:11:6:[1] iter esc: var i int ./shuang.go:11:8:[1] iter esc: i ./shuang.go:11:11:[1] iter esc: 1 ./shuang.go:11:8:[1] iter esc: i := 1 ./shuang.go:11:8:[1] iter escassign: i( a(true) g(4) l(11) x(0) class(PAUTO) ld(1) tc(1) assigned used)[NAME] = 1( l(11) tc(1))[LITERAL] ./shuang.go:11:16:[2] iter esc: i ./shuang.go:11:16:[2] iter esc: num ./shuang.go:11:16:[2] iter esc: i < num ./shuang.go:11:24:[2] iter esc: i ./shuang.go:11:23:[2] iter esc: 1 ./shuang.go:11:24:[2] iter esc: i++ ./shuang.go:11:24:[2] iter escassign: i( a(true) g(4) l(11) x(0) class(PAUTO) ld(1) tc(1) assigned used)[NAME] = 1( l(11) tc(1))[LITERAL] ./shuang.go:12:7:[2] iter esc: res ./shuang.go:12:12:[2] iter esc: a ./shuang.go:12:12:[2] iter esc: var a int ./shuang.go:12:12:[2] iter esc: b ./shuang.go:12:12:[2] iter esc: var b int ./shuang.go:12:12:[2] iter esc: ~r2 ./shuang.go:12:12:[2] iter esc: var ~r2 int ./shuang.go:12:12:[2] iter esc: a ./shuang.go:12:12:[2] iter esc: b ./shuang.go:12:12:[2] iter esc: res ./shuang.go:12:12:[2] iter esc: i ./shuang.go:12:12:[2] iter esc: a, b = res, i ./shuang.go:12:12:[2] iter escassign: a( a(true) l(3) x(0) class(PAUTO) ld(2) tc(1) assigned used)[NAME] = res( a(true) g(3) l(10) x(0) class(PAUTO) ld(1) tc(1) assigned used)[NAME] ./shuang.go:12:12:[2] iter escassign: b( a(true) l(3) x(0) class(PAUTO) ld(2) tc(1) assigned used)[NAME] = i( a(true) g(4) l(11) x(0) class(PAUTO) ld(1) tc(1) assigned used)[NAME] ./shuang.go:12:12:[2] iter esc: ~r2 ./shuang.go:12:12:[2] iter esc: ~r2 = <N> ./shuang.go:12:12:[2] iter esc: ~r2 ./shuang.go:12:12:[2] iter esc: a ./shuang.go:12:12:[2] iter esc: b ./shuang.go:12:12:[2] iter esc: a + b ./shuang.go:12:12:[2] iter esc: ~r2 = a + b ./shuang.go:12:12:[2] iter escassign: ~r2( a(true) l(3) x(0) class(PAUTO) ld(2) tc(1) assigned used)[NAME] = a + b( l(5) tc(1))[+] ./shuang.go:12:12:[2] iter escassign: ~r2( a(true) l(3) x(0) class(PAUTO) ld(2) tc(1) assigned used)[NAME] = a( a(true) l(3) x(0) class(PAUTO) ld(2) tc(1) assigned used)[NAME] ./shuang.go:12:12:[2] iter escassign: ~r2( a(true) l(3) x(0) class(PAUTO) ld(2) tc(1) assigned used)[NAME] = b( a(true) l(3) x(0) class(PAUTO) ld(2) tc(1) assigned used)[NAME] ./shuang.go:12:12:[2] iter esc: .i0 ./shuang.go:12:12:[2] iter esc: goto .i0 ./shuang.go:12:12:[2] iter esc: .i0 ./shuang.go:12:12:[2] iter esc: .i0: ./shuang.go:12:12:.i0: non-looping label ./shuang.go:12:7:[2] iter esc: ~r2 ./shuang.go:12:7:[2] iter esc: int(~r2) ./shuang.go:12:7:[2] iter escassign: int(~r2)( l(12) tc(1) hascall)[CONVNOP] = ~r2( a(true) l(3) x(0) class(PAUTO) ld(2) tc(1) assigned used)[NAME] ./shuang.go:12:7:[2] iter esc: res = int(~r2) ./shuang.go:12:7:[2] iter escassign: res( a(true) g(3) l(10) x(0) class(PAUTO) ld(1) tc(1) assigned used)[NAME] = int(~r2)( l(12) tc(1) hascall)[CONVNOP] ./shuang.go:12:7:[2] iter escassign: res( a(true) g(3) l(10) x(0) class(PAUTO) ld(1) tc(1) assigned used)[NAME] = ~r2( a(true) l(3) x(0) class(PAUTO) ld(2) tc(1) assigned used)[NAME] ./shuang.go:11:2:[1] iter esc: for loop ./shuang.go:14:2:[1] iter esc: res ./shuang.go:14:2:[1] iter esc: return res ./shuang.go:14:2:[1] iter escassign: ~r1( a(true) g(1) l(8) x(8) class(PPARAMOUT))[NAME] = res( a(true) g(3) l(10) x(0) class(PAUTO) ld(1) tc(1) assigned used)[NAME] ./shuang.go:18:2:[1] main esc: n ./shuang.go:18:2:[1] main esc: var n int ./shuang.go:18:4:[1] main esc: n ./shuang.go:18:7:[1] main esc: 10 ./shuang.go:18:4:[1] main esc: n := 10 ./shuang.go:18:4:[1] main escassign: n( a(true) g(1) l(18) x(0) class(PAUTO) ld(1) tc(1) used)[NAME] = 10( l(18) tc(1))[LITERAL] ./shuang.go:19:4:[1] main esc: _ ./shuang.go:19:10:[1] main esc: iter ./shuang.go:19:10:[1] main esc: n ./shuang.go:19:10:[1] main esc: iter(n) ./shuang.go:19:4:[1] main esc: _ = iter(n) /var/folders/9z/kzqrt95n3wj9fq3189s2vvh80000gn/T/go-build416805477/b001/_gomod_.go:7:22:[1] init.0 esc: __debug_modinfo__ /var/folders/9z/kzqrt95n3wj9fq3189s2vvh80000gn/T/go-build416805477/b001/_gomod_.go:7:24:[1] init.0 esc: "0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tdashen\nmod\tdashen\t(devel)\t\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\xd8\xf2" /var/folders/9z/kzqrt95n3wj9fq3189s2vvh80000gn/T/go-build416805477/b001/_gomod_.go:7:22:[1] init.0 esc: __debug_modinfo__ = "0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tdashen\nmod\tdashen\t(devel)\t\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\xd8\xf2" /var/folders/9z/kzqrt95n3wj9fq3189s2vvh80000gn/T/go-build416805477/b001/_gomod_.go:7:22:[1] init.0 escassign: __debug_modinfo__( a(true) l(5) x(0) class(PEXTERN) tc(1) assigned)[NAME] = "0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tdashen\nmod\tdashen\t(devel)\t\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\xd8\xf2"( l(7) tc(1))[LITERAL]
对于 Go 1.16.x版本, 情况有所不同
1 2 3 4 5 6 7
# command-line-arguments ./shuang.go:3:6: can inline add with cost 4 as: func(int, int)int { return a + b } ./shuang.go:8:6: can inline iter with cost 29 as: func(int)int { res := 1; for loop; return res } ./shuang.go:12:12: inlining call to add func(int, int)int { return a + b } ./shuang.go:17:6: can inline main with cost 39 as: func() { n := 100; _ = iter(n) } ./shuang.go:19:10: inlining call to iter func(int)int { res := 1; for loop; return res } ./shuang.go:19:10: inlining call to add func(int, int)int { return a + b }
add,iter,main均可内联.
这应该是某次版本升级带来的优化
内联表:
内联会将函数调用的过程抹掉,这会引入一个新的问题:代码的堆栈信息还能否保证?
举个例子,如果上面的add方法发生了panic,内联之后的程序,还能否准确的打印出堆栈信息?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
package main
funcsub(a, b int) { a = a - b panic("panic information") }
funcmax(a, b int)int { if a < b { sub(a, b) } return a }
funcmain() { x, y := 1, 2 _ = max(x, y) }
在 Go 1.16下,这段代码 go build -gcflags="-m -m" cui.go 结果为:
1 2 3 4 5 6 7
# command-line-arguments ./cui.go:3:6: can inline sub with cost 8 as: func(int, int) { a = a - b; panic("panic information") } ./cui.go:8:6: can inline max with cost 18 as: func(int, int)int { if a < b { sub(a, b) }; return a } ./cui.go:10:6: inlining call to sub func(int, int) { a = a - b; panic("panic information") } ./cui.go:15:6: can inline main with cost 33 as: func() { x, y := 1, 2; _ = max(x, y) } ./cui.go:17:9: inlining call to max func(int, int)int { if a < b { sub(a, b) }; return a } ./cui.go:17:9: inlining call to sub func(int, int) { a = a - b; panic("panic information") }