From: Cherry Zhang Date: Mon, 29 Mar 2021 18:17:18 +0000 (-0400) Subject: cmd/compile: wrap defer/go call with results X-Git-Tag: go1.17beta1~934 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=06ad41642c6e06ddb6faa8575fcc3cfafa6a13d1;p=gostls13.git 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 Reviewed-by: Than McIntosh --- diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 92bddd59da..0062cc5fc7 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -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) } diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index 6e3acc624c..bee3dc3e07 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -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)