]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: wrap defer/go call with results
authorCherry Zhang <cherryyz@google.com>
Mon, 29 Mar 2021 18:17:18 +0000 (14:17 -0400)
committerCherry Zhang <cherryyz@google.com>
Tue, 30 Mar 2021 00:49:14 +0000 (00:49 +0000)
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>
src/cmd/compile/internal/ssagen/ssa.go
src/cmd/compile/internal/walk/order.go

index 92bddd59da0b5204f514775d2a81fba121b40034..0062cc5fc7a150fbe1f976ce8659a7ceb42637c3 100644 (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)
        }
 
index 6e3acc624c45ca397628b08972a74905d495ccb2..bee3dc3e07fe7a2c90ab7335f7f8757a4600490b 100644 (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)