import (
"bufio"
- "internal/buildcfg"
+ "internal/goexperiment"
"internal/testenv"
"io"
"math/bits"
- "os/exec"
"regexp"
"runtime"
"strings"
"getMCache",
"isDirectIface",
"itabHashFunc",
+ "nextslicecap",
"noescape",
"pcvalueCacheKey",
"readUnaligned32",
"gclinkptr.ptr",
"guintptr.ptr",
"writeHeapBitsForAddr",
+ "heapBitsSlice",
"markBits.isMarked",
"muintptr.ptr",
"puintptr.ptr",
"spanOf",
"spanOfUnchecked",
+ "typePointers.nextFast",
"(*gcWork).putFast",
"(*gcWork).tryGetFast",
"(*guintptr).set",
"(*mspan).base",
"(*mspan).markBitsForBase",
"(*mspan).markBitsForIndex",
+ "(*mspan).writeUserArenaHeapBits",
"(*muintptr).set",
"(*puintptr).set",
+ "(*wbBuf).get1",
+ "(*wbBuf).get2",
},
"runtime/internal/sys": {},
"runtime/internal/math": {
"(*Buffer).UnreadByte",
"(*Buffer).tryGrowByReslice",
},
+ "internal/abi": {
+ "UseInterfaceSwitchCache",
+ },
"compress/flate": {
"byLiteral.Len",
"byLiteral.Less",
"AppendRune",
"ValidRune",
},
+ "unicode/utf16": {
+ "Decode",
+ },
"reflect": {
"Value.Bool",
"Value.Bytes",
"net": {
"(*UDPConn).ReadFromUDP",
},
+ "sync": {
+ // Both OnceFunc and its returned closure need to be inlinable so
+ // that the returned closure can be inlined into the caller of OnceFunc.
+ "OnceFunc",
+ "OnceFunc.func2", // The returned closure.
+ // TODO(austin): It would be good to check OnceValue and OnceValues,
+ // too, but currently they aren't reported because they have type
+ // parameters and aren't instantiated in sync.
+ },
"sync/atomic": {
// (*Bool).CompareAndSwap handled below.
"(*Bool).Load",
"(*Uintptr).Load",
"(*Uintptr).Store",
"(*Uintptr).Swap",
- // (*Pointer[T])'s methods' handled below.
+ "(*Pointer[go.shape.int]).CompareAndSwap",
+ "(*Pointer[go.shape.int]).Load",
+ "(*Pointer[go.shape.int]).Store",
+ "(*Pointer[go.shape.int]).Swap",
},
}
if runtime.GOARCH != "386" && runtime.GOARCH != "loong64" && runtime.GOARCH != "mips64" && runtime.GOARCH != "mips64le" && runtime.GOARCH != "riscv64" {
- // nextFreeFast calls sys.Ctz64, which on 386 is implemented in asm and is not inlinable.
+ // nextFreeFast calls sys.TrailingZeros64, which on 386 is implemented in asm and is not inlinable.
// We currently don't have midstack inlining so nextFreeFast is also not inlinable on 386.
- // On loong64, mips64x and riscv64, Ctz64 is not intrinsified and causes nextFreeFast too expensive
- // to inline (Issue 22239).
+ // On loong64, mips64x and riscv64, TrailingZeros64 is not intrinsified and causes nextFreeFast
+ // too expensive to inline (Issue 22239).
want["runtime"] = append(want["runtime"], "nextFreeFast")
// Same behavior for heapBits.nextFast.
want["runtime"] = append(want["runtime"], "heapBits.nextFast")
}
if runtime.GOARCH != "386" {
- // As explained above, Ctz64 and Ctz32 are not Go code on 386.
+ // As explained above, TrailingZeros64 and TrailingZeros32 are not Go code on 386.
// The same applies to Bswap32.
- want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "Ctz64")
- want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "Ctz32")
+ want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "TrailingZeros64")
+ want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "TrailingZeros32")
want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "Bswap32")
}
if bits.UintSize == 64 {
// (*Bool).CompareAndSwap is just over budget on 32-bit systems (386, arm).
want["sync/atomic"] = append(want["sync/atomic"], "(*Bool).CompareAndSwap")
}
- if buildcfg.Experiment.Unified {
- // Non-unified IR does not report "inlining call ..." for atomic.Pointer[T]'s methods.
- // TODO(cuonglm): remove once non-unified IR frontend gone.
- want["sync/atomic"] = append(want["sync/atomic"], "(*Pointer[go.shape.int]).CompareAndSwap")
- want["sync/atomic"] = append(want["sync/atomic"], "(*Pointer[go.shape.int]).Load")
- want["sync/atomic"] = append(want["sync/atomic"], "(*Pointer[go.shape.int]).Store")
- want["sync/atomic"] = append(want["sync/atomic"], "(*Pointer[go.shape.int]).Swap")
- }
switch runtime.GOARCH {
case "386", "wasm", "arm":
}
args := append([]string{"build", "-gcflags=-m -m", "-tags=math_big_pure_go"}, pkgs...)
- cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), args...))
+ cmd := testenv.CleanCmdEnv(testenv.Command(t, testenv.GoToolPath(t), args...))
pr, pw := io.Pipe()
cmd.Stdout = pw
cmd.Stderr = pw
t.Errorf("%s was not inlined: %s", fullName, reason)
}
}
+
+func collectInlCands(msgs string) map[string]struct{} {
+ rv := make(map[string]struct{})
+ lines := strings.Split(msgs, "\n")
+ re := regexp.MustCompile(`^\S+\s+can\s+inline\s+(\S+)`)
+ for _, line := range lines {
+ m := re.FindStringSubmatch(line)
+ if m != nil {
+ rv[m[1]] = struct{}{}
+ }
+ }
+ return rv
+}
+
+func TestIssue56044(t *testing.T) {
+ if testing.Short() {
+ t.Skipf("skipping test: too long for short mode")
+ }
+ if !goexperiment.CoverageRedesign {
+ t.Skipf("skipping new coverage tests (experiment not enabled)")
+ }
+
+ testenv.MustHaveGoBuild(t)
+
+ modes := []string{"-covermode=set", "-covermode=atomic"}
+
+ for _, mode := range modes {
+ // Build the Go runtime with "-m", capturing output.
+ args := []string{"build", "-gcflags=runtime=-m", "runtime"}
+ cmd := testenv.Command(t, testenv.GoToolPath(t), args...)
+ b, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("build failed (%v): %s", err, b)
+ }
+ mbase := collectInlCands(string(b))
+
+ // Redo the build with -cover, also with "-m".
+ args = []string{"build", "-gcflags=runtime=-m", mode, "runtime"}
+ cmd = testenv.Command(t, testenv.GoToolPath(t), args...)
+ b, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("build failed (%v): %s", err, b)
+ }
+ mcov := collectInlCands(string(b))
+
+ // Make sure that there aren't any functions that are marked
+ // as inline candidates at base but not with coverage.
+ for k := range mbase {
+ if _, ok := mcov[k]; !ok {
+ t.Errorf("error: did not find %s in coverage -m output", k)
+ }
+ }
+ }
+}