1
0
mirror of https://github.com/golang/go synced 2024-09-23 13:20:14 -06:00

cmd/compile: set n.Name.Defn for inlined parameters

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>
This commit is contained in:
Matthew Dempsky 2020-09-21 21:24:00 -07:00
parent 8773d14164
commit cced777026
2 changed files with 33 additions and 43 deletions

View File

@ -831,16 +831,19 @@ func (v *reassignVisitor) visitList(l Nodes) *Node {
return nil return nil
} }
func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node { func inlParam(t *types.Field, as *Node, inlvars map[*Node]*Node) *Node {
if n := asNode(t.Nname); n != nil && !n.isBlank() { n := asNode(t.Nname)
inlvar := inlvars[n] if n == nil || n.isBlank() {
if inlvar == nil { return nblank
Fatalf("missing inlvar for %v\n", n)
}
return inlvar
} }
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 var inlgen int
@ -970,14 +973,15 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
continue continue
} }
if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
continue // TODO(mdempsky): Remove once I'm confident
} // this never actually happens. We currently
inlvars[ln] = typecheck(inlvar(ln), ctxExpr) // perform inlining before escape analysis, so
if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM { // nothing should have moved to the heap yet.
ninit.Append(nod(ODCL, inlvars[ln], nil)) Fatalf("impossible: %v", ln)
} }
inlf := typecheck(inlvar(ln), ctxExpr)
inlvars[ln] = inlf
if genDwarfInline > 0 { if genDwarfInline > 0 {
inlf := inlvars[ln]
if ln.Class() == PPARAM { if ln.Class() == PPARAM {
inlf.Name.SetInlFormal(true) inlf.Name.SetInlFormal(true)
} else { } else {
@ -1019,56 +1023,42 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
// Assign arguments to the parameters' temp names. // Assign arguments to the parameters' temp names.
as := nod(OAS2, nil, nil) 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 // For non-dotted calls to variadic functions, we assign the
// variadic parameter's temp name separately. // variadic parameter's temp name separately.
var vas *Node var vas *Node
if fn.IsMethod() { if recv := fn.Type.Recv(); recv != nil {
rcv := fn.Type.Recv() as.List.Append(inlParam(recv, as, inlvars))
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))
}
} }
for _, param := range fn.Type.Params().Fields().Slice() { for _, param := range fn.Type.Params().Fields().Slice() {
// For ordinary parameters or variadic parameters in // For ordinary parameters or variadic parameters in
// dotted calls, just add the variable to the // dotted calls, just add the variable to the
// assignment list, and we're done. // assignment list, and we're done.
if !param.IsDDD() || n.IsDDD() { if !param.IsDDD() || n.IsDDD() {
as.List.Append(tinlvar(param, inlvars)) as.List.Append(inlParam(param, as, inlvars))
continue continue
} }
// Otherwise, we need to collect the remaining values // Otherwise, we need to collect the remaining values
// to pass as a slice. // to pass as a slice.
numvals := n.List.Len()
x := as.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())) as.List.Append(argvar(param.Type, as.List.Len()))
} }
varargs := as.List.Slice()[x:] 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 { if len(varargs) == 0 {
vas.Right = nodnil() vas.Right = nodnil()
vas.Right.Type = param.Type vas.Right.Type = param.Type

View 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",`+ 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":[`+ `"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: 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":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":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)"},`+ `{"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)"},`+