]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/gc: cleanup mkinlcall
authorMatthew Dempsky <mdempsky@google.com>
Fri, 7 Apr 2017 20:47:10 +0000 (13:47 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Fri, 7 Apr 2017 21:30:43 +0000 (21:30 +0000)
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 <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/gc/inl.go

index 7478ee2c7da9fd5e776e51172d77b9ae33d9d800..e5377ed471e338d618b12d0c151491282a4d7b1e 100644 (file)
@@ -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)