Repository: go
Issue: cmd/compile: -m output is missing escape information
Labels: NeedsInvestigation

In #32670 we are considering a new API for golang.org/x/crypto/curve25519. One of the changes I'd like to introduce is not to require the caller to pre-allocate the destination. OTOH, I'd like not to introduce a heap allocation in the process.

I was hoping to be able to use the inliner to inline the variable declaration in the caller, where it has a chance not to escape. I used `-gcflags -m` to verify if it would work.

```
package main

import (
	"crypto/subtle"
	"errors"

	"golang.org/x/crypto/curve25519"
)

func main() {
	scalar, point := make([]byte, 32), make([]byte, 32)
	res, err := X25519(scalar, point)
	if err != nil {
		panic(err)
	}
	println(res)
}

func X25519(scalar, point []byte) ([]byte, error) {
	var dst [32]byte
	return x25519(&dst, scalar, point)
}

func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
	var in, base, zero [32]byte
	copy(in[:], scalar)
	copy(base[:], point)
	curve25519.ScalarMult(dst, &in, &base)
	if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 {
		return nil, errors.New("bad input")
	}
	return dst[:], nil
}
```

In Go 1.12.6 this works as intended. Note `main &dst does not escape`.

```
# play
./inline.go:28:23: inlining call to curve25519.ScalarMult
./inline.go:30:25: inlining call to errors.New
./inline.go:19:6: can inline X25519
./inline.go:12:20: inlining call to X25519
/var/folders/df/mrk3bfz149n8zb5h5p1vp_1m00hbbm/T/go-build156101582/b001/_gomod_.go:6:6: can inline init.0
./inline.go:30:25: error(&errors.errorString literal) escapes to heap
./inline.go:30:25: &errors.errorString literal escapes to heap
./inline.go:24:13: leaking param: dst to result ~r3 level=0
./inline.go:24:28: x25519 scalar does not escape
./inline.go:24:36: x25519 point does not escape
./inline.go:26:9: x25519 in does not escape
./inline.go:27:11: x25519 base does not escape
./inline.go:28:29: x25519 &in does not escape
./inline.go:28:34: x25519 &base does not escape
./inline.go:29:44: x25519 zero does not escape
./inline.go:11:23: main make([]byte, 32) does not escape
./inline.go:11:41: main make([]byte, 32) does not escape
./inline.go:12:20: main &dst does not escape
./inline.go:21:16: &dst escapes to heap
./inline.go:20:6: moved to heap: dst
./inline.go:19:13: X25519 scalar does not escape
./inline.go:19:21: X25519 point does not escape
```

In Go +2f387ac1f3, however, a lot of information is missing from the output. Note that the `&dst escapes to heap` and `main &dst does not escape` lines are gone, along with others.

```
# play
./inline.go:28:23: inlining call to curve25519.ScalarMult
./inline.go:30:25: inlining call to errors.New
./inline.go:19:6: can inline X25519
./inline.go:12:20: inlining call to X25519
./inline.go:24:13: leaking param: dst to result ~r3 level=0
./inline.go:24:28: x25519 scalar does not escape
./inline.go:24:36: x25519 point does not escape
./inline.go:30:25: error(&errors.errorString literal) escapes to heap
./inline.go:30:25: &errors.errorString literal escapes to heap
./inline.go:11:23: main make([]byte, 32) does not escape
./inline.go:11:41: main make([]byte, 32) does not escape
./inline.go:19:13: X25519 scalar does not escape
./inline.go:19:21: X25519 point does not escape
./inline.go:20:6: moved to heap: dst
```

Looking at the SSA it seems the inlined value still doesn't escape, but it's impossible to tell from the `-gcflags -m` output now.

Marking as release-blocker to look into as a regression.

/cc @mdempsky