t.Parallel()
// want is the list of function names (by package) that should
- // be inlined.
+ // be inlinable. If they have no callers in thier packages, they
+ // might not actually be inlined anywhere.
want := map[string][]string{
"runtime": {
// TODO(mvdan): enable these once mid-stack
"(*Buffer).UnreadByte",
"(*Buffer).tryGrowByReslice",
},
+ "compress/flate": {
+ "byLiteral.Len",
+ "byLiteral.Less",
+ "byLiteral.Swap",
+ },
"unicode/utf8": {
"FullRune",
"FullRuneInString",
want["runtime"] = append(want["runtime"], "rotl_31")
}
+ // Functions that must actually be inlined; they must have actual callers.
+ must := map[string]bool{
+ "compress/flate.byLiteral.Len": true,
+ "compress/flate.byLiteral.Less": true,
+ "compress/flate.byLiteral.Swap": true,
+ }
+
notInlinedReason := make(map[string]string)
pkgs := make([]string, 0, len(want))
for pname, fnames := range want {
scanner := bufio.NewScanner(pr)
curPkg := ""
canInline := regexp.MustCompile(`: can inline ([^ ]*)`)
+ haveInlined := regexp.MustCompile(`: inlining call to ([^ ]*)`)
cannotInline := regexp.MustCompile(`: cannot inline ([^ ]*): (.*)`)
for scanner.Scan() {
line := scanner.Text()
curPkg = line[2:]
continue
}
- if m := canInline.FindStringSubmatch(line); m != nil {
+ if m := haveInlined.FindStringSubmatch(line); m != nil {
fname := m[1]
delete(notInlinedReason, curPkg+"."+fname)
continue
}
+ if m := canInline.FindStringSubmatch(line); m != nil {
+ fname := m[1]
+ fullname := curPkg + "." + fname
+ // If function must be inlined somewhere, beeing inlinable is not enough
+ if _, ok := must[fullname]; !ok {
+ delete(notInlinedReason, fullname)
+ continue
+ }
+ }
if m := cannotInline.FindStringSubmatch(line); m != nil {
fname, reason := m[1], m[2]
fullName := curPkg + "." + fname
Curfn = fn
typecheckslice(fn.Nbody.Slice(), Etop)
- // TODO(mdempsky): Investigate why this doesn't work with
- // indexed export. For now, we disable even in non-indexed
- // mode to ensure fair benchmark comparisons and to track down
- // unintended compilation differences.
- if false {
+ // Inline calls within (*T).M wrappers. This is safe because we only
+ // generate those wrappers within the same compilation unit as (T).M.
+ // TODO(mdempsky): Investigate why we can't enable this more generally.
+ if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym != nil {
inlcalls(fn)
}
escAnalyze([]*Node{fn}, false)