]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/ir/func.go
c28761255f3839a42b74a66350343a1da975e96e
[gostls13.git] / src / cmd / compile / internal / ir / func.go
1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package ir
6
7 import (
8         "cmd/compile/internal/base"
9         "cmd/compile/internal/types"
10         "cmd/internal/obj"
11         "cmd/internal/objabi"
12         "cmd/internal/src"
13         "fmt"
14         "strings"
15         "unicode/utf8"
16 )
17
18 // A Func corresponds to a single function in a Go program
19 // (and vice versa: each function is denoted by exactly one *Func).
20 //
21 // There are multiple nodes that represent a Func in the IR.
22 //
23 // The ONAME node (Func.Nname) is used for plain references to it.
24 // The ODCLFUNC node (the Func itself) is used for its declaration code.
25 // The OCLOSURE node (Func.OClosure) is used for a reference to a
26 // function literal.
27 //
28 // An imported function will have an ONAME node which points to a Func
29 // with an empty body.
30 // A declared function or method has an ODCLFUNC (the Func itself) and an ONAME.
31 // A function literal is represented directly by an OCLOSURE, but it also
32 // has an ODCLFUNC (and a matching ONAME) representing the compiled
33 // underlying form of the closure, which accesses the captured variables
34 // using a special data structure passed in a register.
35 //
36 // A method declaration is represented like functions, except f.Sym
37 // will be the qualified method name (e.g., "T.m").
38 //
39 // A method expression (T.M) is represented as an OMETHEXPR node,
40 // in which n.Left and n.Right point to the type and method, respectively.
41 // Each distinct mention of a method expression in the source code
42 // constructs a fresh node.
43 //
44 // A method value (t.M) is represented by ODOTMETH/ODOTINTER
45 // when it is called directly and by OMETHVALUE otherwise.
46 // These are like method expressions, except that for ODOTMETH/ODOTINTER,
47 // the method name is stored in Sym instead of Right.
48 // Each OMETHVALUE ends up being implemented as a new
49 // function, a bit like a closure, with its own ODCLFUNC.
50 // The OMETHVALUE uses n.Func to record the linkage to
51 // the generated ODCLFUNC, but there is no
52 // pointer from the Func back to the OMETHVALUE.
53 type Func struct {
54         miniNode
55         Body Nodes
56
57         Nname    *Name        // ONAME node
58         OClosure *ClosureExpr // OCLOSURE node
59
60         // ONAME nodes for all params/locals for this func/closure, does NOT
61         // include closurevars until transforming closures during walk.
62         // Names must be listed PPARAMs, PPARAMOUTs, then PAUTOs,
63         // with PPARAMs and PPARAMOUTs in order corresponding to the function signature.
64         // Anonymous and blank params are declared as ~pNN (for PPARAMs) and ~rNN (for PPARAMOUTs).
65         Dcl []*Name
66
67         // ClosureVars lists the free variables that are used within a
68         // function literal, but formally declared in an enclosing
69         // function. The variables in this slice are the closure function's
70         // own copy of the variables, which are used within its function
71         // body. They will also each have IsClosureVar set, and will have
72         // Byval set if they're captured by value.
73         ClosureVars []*Name
74
75         // Enclosed functions that need to be compiled.
76         // Populated during walk.
77         Closures []*Func
78
79         // Parents records the parent scope of each scope within a
80         // function. The root scope (0) has no parent, so the i'th
81         // scope's parent is stored at Parents[i-1].
82         Parents []ScopeID
83
84         // Marks records scope boundary changes.
85         Marks []Mark
86
87         FieldTrack map[*obj.LSym]struct{}
88         DebugInfo  interface{}
89         LSym       *obj.LSym // Linker object in this function's native ABI (Func.ABI)
90
91         Inl *Inline
92
93         // funcLitGen and goDeferGen track how many closures have been
94         // created in this function for function literals and go/defer
95         // wrappers, respectively. Used by closureName for creating unique
96         // function names.
97         //
98         // Tracking goDeferGen separately avoids wrappers throwing off
99         // function literal numbering (e.g., runtime/trace_test.TestTraceSymbolize.func11).
100         funcLitGen int32
101         goDeferGen int32
102
103         Label int32 // largest auto-generated label in this function
104
105         Endlineno src.XPos
106         WBPos     src.XPos // position of first write barrier; see SetWBPos
107
108         Pragma PragmaFlag // go:xxx function annotations
109
110         flags bitset16
111
112         // ABI is a function's "definition" ABI. This is the ABI that
113         // this function's generated code is expecting to be called by.
114         //
115         // For most functions, this will be obj.ABIInternal. It may be
116         // a different ABI for functions defined in assembly or ABI wrappers.
117         //
118         // This is included in the export data and tracked across packages.
119         ABI obj.ABI
120         // ABIRefs is the set of ABIs by which this function is referenced.
121         // For ABIs other than this function's definition ABI, the
122         // compiler generates ABI wrapper functions. This is only tracked
123         // within a package.
124         ABIRefs obj.ABISet
125
126         NumDefers  int32 // number of defer calls in the function
127         NumReturns int32 // number of explicit returns in the function
128
129         // nwbrCalls records the LSyms of functions called by this
130         // function for go:nowritebarrierrec analysis. Only filled in
131         // if nowritebarrierrecCheck != nil.
132         NWBRCalls *[]SymAndPos
133
134         // For wrapper functions, WrappedFunc point to the original Func.
135         // Currently only used for go/defer wrappers.
136         WrappedFunc *Func
137
138         // WasmImport is used by the //go:wasmimport directive to store info about
139         // a WebAssembly function import.
140         WasmImport *WasmImport
141 }
142
143 // WasmImport stores metadata associated with the //go:wasmimport pragma.
144 type WasmImport struct {
145         Module string
146         Name   string
147 }
148
149 // NewFunc returns a new Func with the given name and type.
150 //
151 // fpos is the position of the "func" token, and npos is the position
152 // of the name identifier.
153 //
154 // TODO(mdempsky): I suspect there's no need for separate fpos and
155 // npos.
156 func NewFunc(fpos, npos src.XPos, sym *types.Sym, typ *types.Type) *Func {
157         name := NewNameAt(npos, sym, typ)
158         name.Class = PFUNC
159         sym.SetFunc(true)
160
161         fn := &Func{Nname: name}
162         fn.pos = fpos
163         fn.op = ODCLFUNC
164         // Most functions are ABIInternal. The importer or symabis
165         // pass may override this.
166         fn.ABI = obj.ABIInternal
167         fn.SetTypecheck(1)
168
169         name.Func = fn
170
171         return fn
172 }
173
174 func (f *Func) isStmt() {}
175
176 func (n *Func) copy() Node                                  { panic(n.no("copy")) }
177 func (n *Func) doChildren(do func(Node) bool) bool          { return doNodes(n.Body, do) }
178 func (n *Func) editChildren(edit func(Node) Node)           { editNodes(n.Body, edit) }
179 func (n *Func) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.Body, edit) }
180
181 func (f *Func) Type() *types.Type                { return f.Nname.Type() }
182 func (f *Func) Sym() *types.Sym                  { return f.Nname.Sym() }
183 func (f *Func) Linksym() *obj.LSym               { return f.Nname.Linksym() }
184 func (f *Func) LinksymABI(abi obj.ABI) *obj.LSym { return f.Nname.LinksymABI(abi) }
185
186 // An Inline holds fields used for function bodies that can be inlined.
187 type Inline struct {
188         Cost int32 // heuristic cost of inlining this function
189
190         // Copy of Func.Dcl for use during inlining. This copy is needed
191         // because the function's Dcl may change from later compiler
192         // transformations. This field is also populated when a function
193         // from another package is imported and inlined.
194         Dcl     []*Name
195         HaveDcl bool // whether we've loaded Dcl
196
197         // Function properties, encoded as a string (these are used for
198         // making inlining decisions). See cmd/compile/internal/inline/inlheur.
199         Properties string
200
201         // CanDelayResults reports whether it's safe for the inliner to delay
202         // initializing the result parameters until immediately before the
203         // "return" statement.
204         CanDelayResults bool
205 }
206
207 // A Mark represents a scope boundary.
208 type Mark struct {
209         // Pos is the position of the token that marks the scope
210         // change.
211         Pos src.XPos
212
213         // Scope identifies the innermost scope to the right of Pos.
214         Scope ScopeID
215 }
216
217 // A ScopeID represents a lexical scope within a function.
218 type ScopeID int32
219
220 const (
221         funcDupok      = 1 << iota // duplicate definitions ok
222         funcWrapper                // hide frame from users (elide in tracebacks, don't count as a frame for recover())
223         funcABIWrapper             // is an ABI wrapper (also set flagWrapper)
224         funcNeedctxt               // function uses context register (has closure variables)
225         // true if closure inside a function; false if a simple function or a
226         // closure in a global variable initialization
227         funcIsHiddenClosure
228         funcIsDeadcodeClosure        // true if closure is deadcode
229         funcHasDefer                 // contains a defer statement
230         funcNilCheckDisabled         // disable nil checks when compiling this function
231         funcInlinabilityChecked      // inliner has already determined whether the function is inlinable
232         funcNeverReturns             // function never returns (in most cases calls panic(), os.Exit(), or equivalent)
233         funcOpenCodedDeferDisallowed // can't do open-coded defers
234         funcClosureResultsLost       // closure is called indirectly and we lost track of its results; used by escape analysis
235         funcPackageInit              // compiler emitted .init func for package
236 )
237
238 type SymAndPos struct {
239         Sym *obj.LSym // LSym of callee
240         Pos src.XPos  // line of call
241 }
242
243 func (f *Func) Dupok() bool                    { return f.flags&funcDupok != 0 }
244 func (f *Func) Wrapper() bool                  { return f.flags&funcWrapper != 0 }
245 func (f *Func) ABIWrapper() bool               { return f.flags&funcABIWrapper != 0 }
246 func (f *Func) Needctxt() bool                 { return f.flags&funcNeedctxt != 0 }
247 func (f *Func) IsHiddenClosure() bool          { return f.flags&funcIsHiddenClosure != 0 }
248 func (f *Func) IsDeadcodeClosure() bool        { return f.flags&funcIsDeadcodeClosure != 0 }
249 func (f *Func) HasDefer() bool                 { return f.flags&funcHasDefer != 0 }
250 func (f *Func) NilCheckDisabled() bool         { return f.flags&funcNilCheckDisabled != 0 }
251 func (f *Func) InlinabilityChecked() bool      { return f.flags&funcInlinabilityChecked != 0 }
252 func (f *Func) NeverReturns() bool             { return f.flags&funcNeverReturns != 0 }
253 func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 }
254 func (f *Func) ClosureResultsLost() bool       { return f.flags&funcClosureResultsLost != 0 }
255 func (f *Func) IsPackageInit() bool            { return f.flags&funcPackageInit != 0 }
256
257 func (f *Func) SetDupok(b bool)                    { f.flags.set(funcDupok, b) }
258 func (f *Func) SetWrapper(b bool)                  { f.flags.set(funcWrapper, b) }
259 func (f *Func) SetABIWrapper(b bool)               { f.flags.set(funcABIWrapper, b) }
260 func (f *Func) SetNeedctxt(b bool)                 { f.flags.set(funcNeedctxt, b) }
261 func (f *Func) SetIsHiddenClosure(b bool)          { f.flags.set(funcIsHiddenClosure, b) }
262 func (f *Func) SetIsDeadcodeClosure(b bool)        { f.flags.set(funcIsDeadcodeClosure, b) }
263 func (f *Func) SetHasDefer(b bool)                 { f.flags.set(funcHasDefer, b) }
264 func (f *Func) SetNilCheckDisabled(b bool)         { f.flags.set(funcNilCheckDisabled, b) }
265 func (f *Func) SetInlinabilityChecked(b bool)      { f.flags.set(funcInlinabilityChecked, b) }
266 func (f *Func) SetNeverReturns(b bool)             { f.flags.set(funcNeverReturns, b) }
267 func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) }
268 func (f *Func) SetClosureResultsLost(b bool)       { f.flags.set(funcClosureResultsLost, b) }
269 func (f *Func) SetIsPackageInit(b bool)            { f.flags.set(funcPackageInit, b) }
270
271 func (f *Func) SetWBPos(pos src.XPos) {
272         if base.Debug.WB != 0 {
273                 base.WarnfAt(pos, "write barrier")
274         }
275         if !f.WBPos.IsKnown() {
276                 f.WBPos = pos
277         }
278 }
279
280 // FuncName returns the name (without the package) of the function f.
281 func FuncName(f *Func) string {
282         if f == nil || f.Nname == nil {
283                 return "<nil>"
284         }
285         return f.Sym().Name
286 }
287
288 // PkgFuncName returns the name of the function referenced by f, with package
289 // prepended.
290 //
291 // This differs from the compiler's internal convention where local functions
292 // lack a package. This is primarily useful when the ultimate consumer of this
293 // is a human looking at message.
294 func PkgFuncName(f *Func) string {
295         if f == nil || f.Nname == nil {
296                 return "<nil>"
297         }
298         s := f.Sym()
299         pkg := s.Pkg
300
301         return pkg.Path + "." + s.Name
302 }
303
304 // LinkFuncName returns the name of the function f, as it will appear in the
305 // symbol table of the final linked binary.
306 func LinkFuncName(f *Func) string {
307         if f == nil || f.Nname == nil {
308                 return "<nil>"
309         }
310         s := f.Sym()
311         pkg := s.Pkg
312
313         return objabi.PathToPrefix(pkg.Path) + "." + s.Name
314 }
315
316 // ParseLinkFuncName parsers a symbol name (as returned from LinkFuncName) back
317 // to the package path and local symbol name.
318 func ParseLinkFuncName(name string) (pkg, sym string, err error) {
319         pkg, sym = splitPkg(name)
320         if pkg == "" {
321                 return "", "", fmt.Errorf("no package path in name")
322         }
323
324         pkg, err = objabi.PrefixToPath(pkg) // unescape
325         if err != nil {
326                 return "", "", fmt.Errorf("malformed package path: %v", err)
327         }
328
329         return pkg, sym, nil
330 }
331
332 // Borrowed from x/mod.
333 func modPathOK(r rune) bool {
334         if r < utf8.RuneSelf {
335                 return r == '-' || r == '.' || r == '_' || r == '~' ||
336                         '0' <= r && r <= '9' ||
337                         'A' <= r && r <= 'Z' ||
338                         'a' <= r && r <= 'z'
339         }
340         return false
341 }
342
343 func escapedImportPathOK(r rune) bool {
344         return modPathOK(r) || r == '+' || r == '/' || r == '%'
345 }
346
347 // splitPkg splits the full linker symbol name into package and local symbol
348 // name.
349 func splitPkg(name string) (pkgpath, sym string) {
350         // package-sym split is at first dot after last the / that comes before
351         // any characters illegal in a package path.
352
353         lastSlashIdx := 0
354         for i, r := range name {
355                 // Catches cases like:
356                 // * example.foo[sync/atomic.Uint64].
357                 // * example%2ecom.foo[sync/atomic.Uint64].
358                 //
359                 // Note that name is still escaped; unescape occurs after splitPkg.
360                 if !escapedImportPathOK(r) {
361                         break
362                 }
363                 if r == '/' {
364                         lastSlashIdx = i
365                 }
366         }
367         for i := lastSlashIdx; i < len(name); i++ {
368                 r := name[i]
369                 if r == '.' {
370                         return name[:i], name[i+1:]
371                 }
372         }
373
374         return "", name
375 }
376
377 var CurFunc *Func
378
379 // WithFunc invokes do with CurFunc and base.Pos set to curfn and
380 // curfn.Pos(), respectively, and then restores their previous values
381 // before returning.
382 func WithFunc(curfn *Func, do func()) {
383         oldfn, oldpos := CurFunc, base.Pos
384         defer func() { CurFunc, base.Pos = oldfn, oldpos }()
385
386         CurFunc, base.Pos = curfn, curfn.Pos()
387         do()
388 }
389
390 func FuncSymName(s *types.Sym) string {
391         return s.Name + "·f"
392 }
393
394 // ClosureDebugRuntimeCheck applies boilerplate checks for debug flags
395 // and compiling runtime.
396 func ClosureDebugRuntimeCheck(clo *ClosureExpr) {
397         if base.Debug.Closure > 0 {
398                 if clo.Esc() == EscHeap {
399                         base.WarnfAt(clo.Pos(), "heap closure, captured vars = %v", clo.Func.ClosureVars)
400                 } else {
401                         base.WarnfAt(clo.Pos(), "stack closure, captured vars = %v", clo.Func.ClosureVars)
402                 }
403         }
404         if base.Flag.CompilingRuntime && clo.Esc() == EscHeap && !clo.IsGoWrap {
405                 base.ErrorfAt(clo.Pos(), 0, "heap-allocated closure %s, not allowed in runtime", FuncName(clo.Func))
406         }
407 }
408
409 // IsTrivialClosure reports whether closure clo has an
410 // empty list of captured vars.
411 func IsTrivialClosure(clo *ClosureExpr) bool {
412         return len(clo.Func.ClosureVars) == 0
413 }
414
415 // globClosgen is like Func.Closgen, but for the global scope.
416 var globClosgen int32
417
418 // closureName generates a new unique name for a closure within outerfn at pos.
419 func closureName(outerfn *Func, pos src.XPos, why Op) *types.Sym {
420         pkg := types.LocalPkg
421         outer := "glob."
422         var prefix string
423         switch why {
424         default:
425                 base.FatalfAt(pos, "closureName: bad Op: %v", why)
426         case OCLOSURE:
427                 if outerfn == nil || outerfn.OClosure == nil {
428                         prefix = "func"
429                 }
430         case OGO:
431                 prefix = "gowrap"
432         case ODEFER:
433                 prefix = "deferwrap"
434         }
435         gen := &globClosgen
436
437         // There may be multiple functions named "_". In those
438         // cases, we can't use their individual Closgens as it
439         // would lead to name clashes.
440         if outerfn != nil && !IsBlank(outerfn.Nname) {
441                 pkg = outerfn.Sym().Pkg
442                 outer = FuncName(outerfn)
443
444                 if why == OCLOSURE {
445                         gen = &outerfn.funcLitGen
446                 } else {
447                         gen = &outerfn.goDeferGen
448                 }
449         }
450
451         // If this closure was created due to inlining, then incorporate any
452         // inlined functions' names into the closure's linker symbol name
453         // too (#60324).
454         if inlIndex := base.Ctxt.InnermostPos(pos).Base().InliningIndex(); inlIndex >= 0 {
455                 names := []string{outer}
456                 base.Ctxt.InlTree.AllParents(inlIndex, func(call obj.InlinedCall) {
457                         names = append(names, call.Name)
458                 })
459                 outer = strings.Join(names, ".")
460         }
461
462         *gen++
463         return pkg.Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
464 }
465
466 // NewClosureFunc creates a new Func to represent a function literal
467 // with the given type.
468 //
469 // fpos the position used for the underlying ODCLFUNC and ONAME,
470 // whereas cpos is the position used for the OCLOSURE. They're
471 // separate because in the presence of inlining, the OCLOSURE node
472 // should have an inline-adjusted position, whereas the ODCLFUNC and
473 // ONAME must not.
474 //
475 // outerfn is the enclosing function, if any. The returned function is
476 // appending to pkg.Funcs.
477 //
478 // why is the reason we're generating this Func. It can be OCLOSURE
479 // (for a normal function literal) or OGO or ODEFER (for wrapping a
480 // call expression that has parameters or results).
481 func NewClosureFunc(fpos, cpos src.XPos, why Op, typ *types.Type, outerfn *Func, pkg *Package) *Func {
482         fn := NewFunc(fpos, fpos, closureName(outerfn, cpos, why), typ)
483         fn.SetIsHiddenClosure(outerfn != nil)
484
485         clo := &ClosureExpr{Func: fn}
486         clo.op = OCLOSURE
487         clo.pos = cpos
488         clo.SetType(typ)
489         clo.SetTypecheck(1)
490         fn.OClosure = clo
491
492         fn.Nname.Defn = fn
493         pkg.Funcs = append(pkg.Funcs, fn)
494
495         return fn
496 }
497
498 // IsFuncPCIntrinsic returns whether n is a direct call of internal/abi.FuncPCABIxxx functions.
499 func IsFuncPCIntrinsic(n *CallExpr) bool {
500         if n.Op() != OCALLFUNC || n.Fun.Op() != ONAME {
501                 return false
502         }
503         fn := n.Fun.(*Name).Sym()
504         return (fn.Name == "FuncPCABI0" || fn.Name == "FuncPCABIInternal") &&
505                 fn.Pkg.Path == "internal/abi"
506 }
507
508 // IsIfaceOfFunc inspects whether n is an interface conversion from a direct
509 // reference of a func. If so, it returns referenced Func; otherwise nil.
510 //
511 // This is only usable before walk.walkConvertInterface, which converts to an
512 // OMAKEFACE.
513 func IsIfaceOfFunc(n Node) *Func {
514         if n, ok := n.(*ConvExpr); ok && n.Op() == OCONVIFACE {
515                 if name, ok := n.X.(*Name); ok && name.Op() == ONAME && name.Class == PFUNC {
516                         return name.Func
517                 }
518         }
519         return nil
520 }
521
522 // FuncPC returns a uintptr-typed expression that evaluates to the PC of a
523 // function as uintptr, as returned by internal/abi.FuncPC{ABI0,ABIInternal}.
524 //
525 // n should be a Node of an interface type, as is passed to
526 // internal/abi.FuncPC{ABI0,ABIInternal}.
527 //
528 // TODO(prattmic): Since n is simply an interface{} there is no assertion that
529 // it is actually a function at all. Perhaps we should emit a runtime type
530 // assertion?
531 func FuncPC(pos src.XPos, n Node, wantABI obj.ABI) Node {
532         if !n.Type().IsInterface() {
533                 base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an interface value, got %v", wantABI, n.Type())
534         }
535
536         if fn := IsIfaceOfFunc(n); fn != nil {
537                 name := fn.Nname
538                 abi := fn.ABI
539                 if abi != wantABI {
540                         base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an %v function, %s is defined as %v", wantABI, wantABI, name.Sym().Name, abi)
541                 }
542                 var e Node = NewLinksymExpr(pos, name.Sym().LinksymABI(abi), types.Types[types.TUINTPTR])
543                 e = NewAddrExpr(pos, e)
544                 e.SetType(types.Types[types.TUINTPTR].PtrTo())
545                 e = NewConvExpr(pos, OCONVNOP, types.Types[types.TUINTPTR], e)
546                 e.SetTypecheck(1)
547                 return e
548         }
549         // fn is not a defined function. It must be ABIInternal.
550         // Read the address from func value, i.e. *(*uintptr)(idata(fn)).
551         if wantABI != obj.ABIInternal {
552                 base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s does not accept func expression, which is ABIInternal", wantABI)
553         }
554         var e Node = NewUnaryExpr(pos, OIDATA, n)
555         e.SetType(types.Types[types.TUINTPTR].PtrTo())
556         e.SetTypecheck(1)
557         e = NewStarExpr(pos, e)
558         e.SetType(types.Types[types.TUINTPTR])
559         e.SetTypecheck(1)
560         return e
561 }
562
563 // DeclareParams creates Names for all of the parameters in fn's
564 // signature and adds them to fn.Dcl.
565 //
566 // If setNname is true, then it also sets types.Field.Nname for each
567 // parameter.
568 func (fn *Func) DeclareParams(setNname bool) {
569         if fn.Dcl != nil {
570                 base.FatalfAt(fn.Pos(), "%v already has Dcl", fn)
571         }
572
573         declareParams := func(params []*types.Field, ctxt Class, prefix string, offset int) {
574                 for i, param := range params {
575                         sym := param.Sym
576                         if sym == nil || sym.IsBlank() {
577                                 sym = fn.Sym().Pkg.LookupNum(prefix, i)
578                         }
579
580                         name := NewNameAt(param.Pos, sym, param.Type)
581                         name.Class = ctxt
582                         name.Curfn = fn
583                         fn.Dcl[offset+i] = name
584
585                         if setNname {
586                                 param.Nname = name
587                         }
588                 }
589         }
590
591         sig := fn.Type()
592         params := sig.RecvParams()
593         results := sig.Results()
594
595         fn.Dcl = make([]*Name, len(params)+len(results))
596         declareParams(params, PPARAM, "~p", 0)
597         declareParams(results, PPARAMOUT, "~r", len(params))
598 }