From: Matthew Dempsky Date: Fri, 7 Apr 2017 20:47:10 +0000 (-0700) Subject: cmd/compile/internal/gc: cleanup mkinlcall X-Git-Tag: go1.9beta1~784 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ce9bef261cefb7a00a90a4aa592774438f1b7f52;p=gostls13.git cmd/compile/internal/gc: cleanup mkinlcall I had too many failed attempts trying to remove iterFields that I decided to overhaul this function. Much simpler and easier to understand now (at least IMO). Passes toolstash-check -all. Change-Id: I41d00642a969698df3f4689e41a386346b966638 Reviewed-on: https://go-review.googlesource.com/39856 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index 7478ee2c7d..e5377ed471 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -564,74 +564,70 @@ func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node { var inlgen int -// if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL. +// If n is a call, and fn is a function with an inlinable body, +// return an OINLCALL. // On return ninit has the parameter assignments, the nbody is the // inlined function body and list, rlist contain the input, output // parameters. // The result of mkinlcall1 MUST be assigned back to n, e.g. // n.Left = mkinlcall1(n.Left, fn, isddd) func mkinlcall1(n *Node, fn *Node, isddd bool) *Node { - // For variadic fn. if fn.Func.Inl.Len() == 0 { + // No inlinable body. return n } if fn == Curfn || fn.Name.Defn == Curfn { + // Can't recursively inline a function into itself. return n } - inlvars := make(map[*Node]*Node) - if Debug['l'] < 2 { typecheckinl(fn) } - // Bingo, we have a function node, and it has an inlineable body + // We have a function node, and it has an inlineable body. if Debug['m'] > 1 { fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, fn.Func.Inl) } else if Debug['m'] != 0 { fmt.Printf("%v: inlining call to %v\n", n.Line(), fn) } - if Debug['m'] > 2 { fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n) } ninit := n.Ninit - //dumplist("ninit pre", ninit); - + // Find declarations corresponding to inlineable body. var dcl []*Node if fn.Name.Defn != nil { - // local function - dcl = fn.Func.Inldcl.Slice() + dcl = fn.Func.Inldcl.Slice() // local function } else { - // imported function - dcl = fn.Func.Dcl + dcl = fn.Func.Dcl // imported function } - var retvars []*Node - i := 0 - - // Make temp names to use instead of the originals + // Make temp names to use instead of the originals. + inlvars := make(map[*Node]*Node) for _, ln := range dcl { + if ln.Op != ONAME { + continue + } if ln.Class == PPARAMOUT { // return values handled below. continue } if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap continue } - if ln.Op == ONAME { - inlvars[ln] = typecheck(inlvar(ln), Erv) - if ln.Class == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class == PPARAM { - ninit.Append(nod(ODCL, inlvars[ln], nil)) - } + inlvars[ln] = typecheck(inlvar(ln), Erv) + if ln.Class == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class == PPARAM { + ninit.Append(nod(ODCL, inlvars[ln], nil)) } } // temporaries for return values. - var m *Node - for _, t := range fn.Type.Results().Fields().Slice() { + var retvars []*Node + for i, t := range fn.Type.Results().Fields().Slice() { + var m *Node if t != nil && asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) { m = inlvar(asNode(t.Nname)) m = typecheck(m, Erv) @@ -639,152 +635,73 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node { } else { // anonymous return values, synthesize names for use in assignment that replaces return m = retvar(t, i) - i++ } ninit.Append(nod(ODCL, m, nil)) retvars = append(retvars, m) } - // assign receiver. - if fn.IsMethod() && n.Left.Op == ODOTMETH { - // method call with a receiver. - t := fn.Type.Recv() - - if t != nil && t.Nname != nil && !isblank(asNode(t.Nname)) && inlvars[asNode(t.Nname)] == nil { - Fatalf("missing inlvar for %v\n", asNode(t.Nname)) - } - if n.Left.Left == nil { - Fatalf("method call without receiver: %+v", n) - } - if t == nil { - Fatalf("method call unknown receiver type: %+v", n) - } - as := nod(OAS, tinlvar(t, inlvars), n.Left.Left) - if as != nil { - as = typecheck(as, Etop) - ninit.Append(as) - } - } - - // check if inlined function is variadic. - variadic := false - - var varargtype *types.Type - varargcount := 0 - for _, t := range fn.Type.Params().Fields().Slice() { - if t.Isddd() { - variadic = true - varargtype = t.Type - } - } + // Assign arguments to the parameters' temp names. + as := nod(OAS2, nil, nil) + as.Rlist.Set(n.List.Slice()) - // but if argument is dotted too forget about variadicity. - if variadic && isddd { - variadic = false - } + // For non-dotted calls to variadic functions, we assign the + // variadic parameter's temp name separately. + var vas *Node - // check if argument is actually a returned tuple from call. - multiret := 0 + if fn.IsMethod() { + rcv := fn.Type.Recv() - if n.List.Len() == 1 { - switch n.List.First().Op { - case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH: - if n.List.First().Left.Type.Results().NumFields() > 1 { - multiret = n.List.First().Left.Type.Results().NumFields() - 1 + 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, Etop) + 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 variadic { - varargcount = n.List.Len() + multiret - if n.Left.Op != ODOTMETH { - varargcount -= fn.Type.Recvs().NumFields() - } - varargcount -= fn.Type.Params().NumFields() - 1 - } - - // assign arguments to the parameters' temp names - as := nod(OAS2, nil, nil) - - as.Rlist.Set(n.List.Slice()) - li := 0 - - // TODO: if len(nlist) == 1 but multiple args, check that n->list->n is a call? - if fn.IsMethod() && n.Left.Op != ODOTMETH { - // non-method call to method - if n.List.Len() == 0 { - Fatalf("non-method call to method without first arg: %+v", n) + 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() || isddd { + as.List.Append(tinlvar(param, inlvars)) + continue } - // append receiver inlvar to LHS. - t := fn.Type.Recv() + // Otherwise, we need to collect the remaining values + // to pass as a slice. - if t != nil && t.Nname != nil && !isblank(asNode(t.Nname)) && inlvars[asNode(t.Nname)] == nil { - Fatalf("missing inlvar for %v\n", asNode(t.Nname)) - } - if t == nil { - Fatalf("method call unknown receiver type: %+v", n) + numvals := n.List.Len() + if numvals == 1 && n.List.First().Type.IsFuncArgStruct() { + numvals = n.List.First().Type.NumFields() } - as.List.Append(tinlvar(t, inlvars)) - li++ - } - - // append ordinary arguments to LHS. - chkargcount := n.List.Len() > 1 - - var vararg *Node // the slice argument to a variadic call - var varargs []*Node // the list of LHS names to put in vararg. - if !chkargcount { - // 0 or 1 expression on RHS. - var i int - for _, t := range fn.Type.Params().Fields().Slice() { - if variadic && t.Isddd() { - vararg = tinlvar(t, inlvars) - for i = 0; i < varargcount && li < n.List.Len(); i++ { - m = argvar(varargtype, i) - varargs = append(varargs, m) - as.List.Append(m) - } - - break - } - as.List.Append(tinlvar(t, inlvars)) - } - } else { - // match arguments except final variadic (unless the call is dotted itself) - t, it := types.IterFields(fn.Type.Params()) - for t != nil { - if li >= n.List.Len() { - break - } - if variadic && t.Isddd() { - break - } - as.List.Append(tinlvar(t, inlvars)) - t = it.Next() - li++ - } - - // match varargcount arguments with variadic parameters. - if variadic && t != nil && t.Isddd() { - vararg = tinlvar(t, inlvars) - var i int - for i = 0; i < varargcount && li < n.List.Len(); i++ { - m = argvar(varargtype, i) - varargs = append(varargs, m) - as.List.Append(m) - li++ - } - - if i == varargcount { - t = it.Next() - } + x := as.List.Len() + for as.List.Len() < numvals { + as.List.Append(argvar(param.Type, as.List.Len())) } + varargs := as.List.Slice()[x:] - if li < n.List.Len() || t != nil { - Fatalf("arg count mismatch: %#v vs %.v\n", fn.Type.Params(), n.List) + vas = nod(OAS, tinlvar(param, inlvars), nil) + if len(varargs) == 0 { + vas.Right = nodnil() + vas.Right.Type = param.Type + } else { + vas.Right = nod(OCOMPLIT, nil, typenod(param.Type)) + vas.Right.List.Set(varargs) } } @@ -793,23 +710,12 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node { ninit.Append(as) } - // turn the variadic args into a slice. - if variadic { - as = nod(OAS, vararg, nil) - if varargcount == 0 { - as.Right = nodnil() - as.Right.Type = varargtype - } else { - varslicetype := types.NewSlice(varargtype.Elem()) - as.Right = nod(OCOMPLIT, nil, typenod(varslicetype)) - as.Right.List.Set(varargs) - } - - as = typecheck(as, Etop) - ninit.Append(as) + if vas != nil { + vas = typecheck(vas, Etop) + ninit.Append(vas) } - // zero the outparams + // Zero the return parameters. for _, n := range retvars { as = nod(OAS, n, nil) as = typecheck(as, Etop) @@ -838,7 +744,6 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node { //dumplist("ninit post", ninit); call := nod(OINLCALL, nil, nil) - call.Ninit.Set(ninit.Slice()) call.Nbody.Set(body) call.Rlist.Set(retvars)