cmd/compile: wrap defer/go call with results

CL 298669 implemented wrapping for defer/go calls so the function
being called with defer or go statement has no arguments. This
simplifies the compiler and the runtime, especially with the
new ABI.

Currently, it does not wrap functions that has no arguments but
only results. For defer/go calls, the results are not used. But
the runtime needs to allocate stack space for the callee to store
the results. Wrapping functions with results makes the runtime
simpler.

TODO: maybe not wrap if all results are in registers.

Updates #40724.

Change-Id: I74d2f4db1cbf9979afbcd846facb30d11d72ab23
Reviewed-on: https://go-review.googlesource.com/c/go/+/305550
Trust: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
Cherry Zhang 2021-03-29 14:17:18 -04:00
parent e27f3966bb
commit 06ad41642c
2 changed files with 8 additions and 5 deletions

View file

@ -4608,8 +4608,8 @@ func (s *state) openDeferRecord(n *ir.CallExpr) {
var args []*ssa.Value
var argNodes []*ir.Name
if objabi.Experiment.RegabiDefer && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER) {
s.Fatalf("defer call with arguments: %v", n)
if objabi.Experiment.RegabiDefer && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0) {
s.Fatalf("defer call with arguments or results: %v", n)
}
opendefer := &openDeferInfo{
@ -4860,7 +4860,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
}
}
if objabi.Experiment.RegabiDefer && k != callNormal && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER) {
if objabi.Experiment.RegabiDefer && k != callNormal && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0) {
s.Fatalf("go/defer call with arguments: %v", n)
}

View file

@ -1504,7 +1504,7 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) {
panic("unhandled op")
}
// No need to wrap if called func has no args and no receiver.
// No need to wrap if called func has no args, no receiver, and no results.
// However in the case of "defer func() { ... }()" we need to
// protect against the possibility of directClosureCall rewriting
// things so that the call does have arguments.
@ -1514,7 +1514,10 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) {
//
// Also do wrap builtin functions, because they may be expanded to
// calls with arguments (e.g. ORECOVER).
if len(callArgs) == 0 && call.Op() == ir.OCALLFUNC {
//
// TODO: maybe not wrap if the called function has no arguments and
// only in-register results?
if len(callArgs) == 0 && call.Op() == ir.OCALLFUNC && callX.Type().NumResults() == 0 {
if c, ok := call.(*ir.CallExpr); ok && callX != nil && callX.Op() == ir.OCLOSURE {
cloFunc := callX.(*ir.ClosureExpr).Func
cloFunc.SetClosureCalled(false)