1 // Copyright 2023 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.
5 // WARNING: Please avoid updating this file. If this file needs to be updated,
6 // then a new devirt.pprof file should be generated:
8 // $ cd $GOROOT/src/cmd/compile/internal/test/testdata/pgo/devirtualize/
9 // $ go mod init example.com/pgo/devirtualize
10 // $ go test -bench=. -cpuprofile ./devirt.pprof
14 // Devirtualization of callees from transitive dependencies should work even if
15 // they aren't directly referenced in the package. See #61577.
17 // Dots in the last package path component are escaped in symbol names. Use one
18 // to ensure the escaping doesn't break lookup.
22 "example.com/pgo/devirtualize/mult.pkg"
27 type Adder interface {
33 func (Add) Add(a, b int) int {
34 for i := 0; i < 1000; i++ {
42 func (Sub) Add(a, b int) int {
43 for i := 0; i < 1000; i++ {
49 // ExerciseIface calls mostly a1 and m1.
52 func ExerciseIface(iter int, a1, a2 Adder, m1, m2 mult.Multiplier) int {
53 // The call below must evaluate selectA() to determine the receiver to
54 // use. This should happen exactly once per iteration. Assert that is
55 // the case to ensure the IR manipulation does not result in over- or
58 selectA := func(gotI int) Adder {
60 panic(fmt.Sprintf("selectA not called once per iteration; got i %d want %d", gotI, selectI))
70 one := func(gotI int) int {
72 panic(fmt.Sprintf("one not called once per iteration; got i %d want %d", gotI, oneI))
76 // The function value must be evaluated before arguments, so
77 // selectI must have been incremented already.
79 panic(fmt.Sprintf("selectA not called before not called before one; got i %d want %d", selectI, oneI))
86 for i := 0; i < iter; i++ {
92 // N.B. Profiles only distinguish calls on a per-line level,
93 // making the two calls ambiguous. However because the
94 // interfaces and implementations are mutually exclusive,
95 // devirtualization can still select the correct callee for
98 // If they were not mutually exclusive (for example, two Add
99 // calls), then we could not definitively select the correct
101 val += m.Multiply(42, selectA(i).Add(one(i), 2))
106 type AddFunc func(int, int) int
108 func AddFn(a, b int) int {
109 for i := 0; i < 1000; i++ {
115 func SubFn(a, b int) int {
116 for i := 0; i < 1000; i++ {
122 // ExerciseFuncConcrete calls mostly a1 and m1.
125 func ExerciseFuncConcrete(iter int, a1, a2 AddFunc, m1, m2 mult.MultFunc) int {
126 // The call below must evaluate selectA() to determine the function to
127 // call. This should happen exactly once per iteration. Assert that is
128 // the case to ensure the IR manipulation does not result in over- or
131 selectA := func(gotI int) AddFunc {
133 panic(fmt.Sprintf("selectA not called once per iteration; got i %d want %d", gotI, selectI))
143 one := func(gotI int) int {
145 panic(fmt.Sprintf("one not called once per iteration; got i %d want %d", gotI, oneI))
149 // The function value must be evaluated before arguments, so
150 // selectI must have been incremented already.
152 panic(fmt.Sprintf("selectA not called before not called before one; got i %d want %d", selectI, oneI))
159 for i := 0; i < iter; i++ {
165 // N.B. Profiles only distinguish calls on a per-line level,
166 // making the two calls ambiguous. However because the
167 // function types are mutually exclusive, devirtualization can
168 // still select the correct callee for each.
170 // If they were not mutually exclusive (for example, two
171 // AddFunc calls), then we could not definitively select the
173 val += int(m(42, int64(selectA(i)(one(i), 2))))
178 // ExerciseFuncField calls mostly a1 and m1.
180 // This is a simplified version of ExerciseFuncConcrete, but accessing the
181 // function values via a struct field.
184 func ExerciseFuncField(iter int, a1, a2 AddFunc, m1, m2 mult.MultFunc) int {
191 for i := 0; i < iter; i++ {
199 // N.B. Profiles only distinguish calls on a per-line level,
200 // making the two calls ambiguous. However because the
201 // function types are mutually exclusive, devirtualization can
202 // still select the correct callee for each.
204 // If they were not mutually exclusive (for example, two
205 // AddFunc calls), then we could not definitively select the
207 val += int(ops.m(42, int64(ops.a(1, 2))))
213 func AddClosure() AddFunc {
214 // Implicit closure by capturing the receiver.
220 func SubClosure() AddFunc {
225 // ExerciseFuncClosure calls mostly a1 and m1.
227 // This is a simplified version of ExerciseFuncConcrete, but we need two
228 // distinct call sites to test two different types of function values.
231 func ExerciseFuncClosure(iter int, a1, a2 AddFunc, m1, m2 mult.MultFunc) int {
233 for i := 0; i < iter; i++ {
241 // N.B. Profiles only distinguish calls on a per-line level,
242 // making the two calls ambiguous. However because the
243 // function types are mutually exclusive, devirtualization can
244 // still select the correct callee for each.
246 // If they were not mutually exclusive (for example, two
247 // AddFunc calls), then we could not definitively select the
249 val += int(m(42, int64(a(1, 2))))