]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: set n.Name.Defn for inlined parameters
authorMatthew Dempsky <mdempsky@google.com>
Tue, 22 Sep 2020 04:24:00 +0000 (21:24 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 15 Oct 2020 18:25:47 +0000 (18:25 +0000)
Normally, when variables are declared and initialized using ":=", we
set the variable's n.Name.Defn to point to the initialization
assignment node (i.e., OAS or OAS2). Further, some frontend
optimizations look for variables that are initialized but never
reassigned.

However, when inl.go inlines calls, it was declaring the inlined
variables, and then separately assigning to them. This CL changes
inl.go tweaks the AST to fit the combined declaration+initialization
pattern.

This isn't terribly useful by itself, but it allows further followup
optimizations.

Updates #41474.

Change-Id: I62a9752c60414305679e0ed15a6563baa0224efa
Reviewed-on: https://go-review.googlesource.com/c/go/+/256457
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
src/cmd/compile/internal/gc/inl.go
src/cmd/compile/internal/logopt/logopt_test.go

index fa5b3ec698be297a6b704df69af5c5f0cc0cd731..5740864b12f9ac35804581457ba758b22028d973 100644 (file)
@@ -831,16 +831,19 @@ func (v *reassignVisitor) visitList(l Nodes) *Node {
        return nil
 }
 
-func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node {
-       if n := asNode(t.Nname); n != nil && !n.isBlank() {
-               inlvar := inlvars[n]
-               if inlvar == nil {
-                       Fatalf("missing inlvar for %v\n", n)
-               }
-               return inlvar
+func inlParam(t *types.Field, as *Node, inlvars map[*Node]*Node) *Node {
+       n := asNode(t.Nname)
+       if n == nil || n.isBlank() {
+               return nblank
        }
 
-       return typecheck(nblank, ctxExpr|ctxAssign)
+       inlvar := inlvars[n]
+       if inlvar == nil {
+               Fatalf("missing inlvar for %v", n)
+       }
+       as.Ninit.Append(nod(ODCL, inlvar, nil))
+       inlvar.Name.Defn = as
+       return inlvar
 }
 
 var inlgen int
@@ -970,14 +973,15 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
                        continue
                }
                if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
-                       continue
-               }
-               inlvars[ln] = typecheck(inlvar(ln), ctxExpr)
-               if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM {
-                       ninit.Append(nod(ODCL, inlvars[ln], nil))
+                       // TODO(mdempsky): Remove once I'm confident
+                       // this never actually happens. We currently
+                       // perform inlining before escape analysis, so
+                       // nothing should have moved to the heap yet.
+                       Fatalf("impossible: %v", ln)
                }
+               inlf := typecheck(inlvar(ln), ctxExpr)
+               inlvars[ln] = inlf
                if genDwarfInline > 0 {
-                       inlf := inlvars[ln]
                        if ln.Class() == PPARAM {
                                inlf.Name.SetInlFormal(true)
                        } else {
@@ -1019,56 +1023,42 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
 
        // Assign arguments to the parameters' temp names.
        as := nod(OAS2, nil, nil)
-       as.Rlist.Set(n.List.Slice())
+       as.SetColas(true)
+       if n.Op == OCALLMETH {
+               if n.Left.Left == nil {
+                       Fatalf("method call without receiver: %+v", n)
+               }
+               as.Rlist.Append(n.Left.Left)
+       }
+       as.Rlist.Append(n.List.Slice()...)
 
        // For non-dotted calls to variadic functions, we assign the
        // variadic parameter's temp name separately.
        var vas *Node
 
-       if fn.IsMethod() {
-               rcv := fn.Type.Recv()
-
-               if n.Left.Op == ODOTMETH {
-                       // For x.M(...), assign x directly to the
-                       // receiver parameter.
-                       if n.Left.Left == nil {
-                               Fatalf("method call without receiver: %+v", n)
-                       }
-                       ras := nod(OAS, tinlvar(rcv, inlvars), n.Left.Left)
-                       ras = typecheck(ras, ctxStmt)
-                       ninit.Append(ras)
-               } else {
-                       // For T.M(...), add the receiver parameter to
-                       // as.List, so it's assigned by the normal
-                       // arguments.
-                       if as.Rlist.Len() == 0 {
-                               Fatalf("non-method call to method without first arg: %+v", n)
-                       }
-                       as.List.Append(tinlvar(rcv, inlvars))
-               }
+       if recv := fn.Type.Recv(); recv != nil {
+               as.List.Append(inlParam(recv, as, inlvars))
        }
-
        for _, param := range fn.Type.Params().Fields().Slice() {
                // For ordinary parameters or variadic parameters in
                // dotted calls, just add the variable to the
                // assignment list, and we're done.
                if !param.IsDDD() || n.IsDDD() {
-                       as.List.Append(tinlvar(param, inlvars))
+                       as.List.Append(inlParam(param, as, inlvars))
                        continue
                }
 
                // Otherwise, we need to collect the remaining values
                // to pass as a slice.
 
-               numvals := n.List.Len()
-
                x := as.List.Len()
-               for as.List.Len() < numvals {
+               for as.List.Len() < as.Rlist.Len() {
                        as.List.Append(argvar(param.Type, as.List.Len()))
                }
                varargs := as.List.Slice()[x:]
 
-               vas = nod(OAS, tinlvar(param, inlvars), nil)
+               vas = nod(OAS, nil, nil)
+               vas.Left = inlParam(param, vas, inlvars)
                if len(varargs) == 0 {
                        vas.Right = nodnil()
                        vas.Right.Type = param.Type
index b57a07f12c69a0954cf553653654c00a455c7780..fb71e142e3c58f69a57ac551e86aed5a1d5d3217 100644 (file)
@@ -213,7 +213,7 @@ func s15a8(x *[15]int64) [15]int64 {
                want(t, slogged, `{"range":{"start":{"line":7,"character":13},"end":{"line":7,"character":13}},"severity":3,"code":"leak","source":"go compiler","message":"parameter z leaks to ~r2 with derefs=0",`+
                        `"relatedInformation":[`+
                        `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow:    flow: y = z:"},`+
-                       `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow:      from y = \u003cN\u003e (assign-pair)"},`+
+                       `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow:      from y := z (assign-pair)"},`+
                        `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow:    flow: ~r1 = y:"},`+
                        `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
                        `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow:      from y.b (dot of pointer)"},`+