1 // Copyright 2009 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.
11 "cmd/compile/internal/base"
12 "cmd/compile/internal/ir"
13 "cmd/compile/internal/types"
17 var funcStack []*ir.Func // stack of previous values of ir.CurFunc
19 // DeclFunc creates and returns ONAMEs for the parameters and results
20 // of the given function. It also sets ir.CurFunc, and adds fn to
23 // After the caller is done constructing fn, it must call
25 func DeclFunc(fn *ir.Func) (params, results []*ir.Name) {
28 // Currently, DeclFunc is only used to create normal functions, not
29 // methods. If a use case for creating methods shows up, we can
30 // extend it to support those too.
31 if typ.Recv() != nil {
32 base.FatalfAt(fn.Pos(), "unexpected receiver parameter")
35 params = declareParams(fn, ir.PPARAM, typ.Params())
36 results = declareParams(fn, ir.PPARAMOUT, typ.Results())
38 funcStack = append(funcStack, ir.CurFunc)
42 Target.Funcs = append(Target.Funcs, fn)
47 // FinishFuncBody restores ir.CurFunc to its state before the last
49 func FinishFuncBody() {
50 funcStack, ir.CurFunc = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
53 func CheckFuncStack() {
54 if len(funcStack) != 0 {
55 base.Fatalf("funcStack is non-empty: %v", len(funcStack))
59 func declareParams(fn *ir.Func, ctxt ir.Class, params []*types.Field) []*ir.Name {
60 names := make([]*ir.Name, len(params))
61 for i, param := range params {
62 names[i] = declareParam(fn, ctxt, i, param)
67 func declareParam(fn *ir.Func, ctxt ir.Class, i int, param *types.Field) *ir.Name {
69 if ctxt == ir.PPARAMOUT {
71 // Name so that escape analysis can track it. ~r stands for 'result'.
72 sym = LookupNum("~r", i)
73 } else if sym.IsBlank() {
74 // Give it a name so we can assign to it during return. ~b stands for 'blank'.
75 // The name must be different from ~r above because if you have
78 // f is allowed to use a plain 'return' with no arguments, while g is not.
79 // So the two cases must be distinguished.
80 sym = LookupNum("~b", i)
88 name := fn.NewLocal(param.Pos, sym, ctxt, param.Type)
93 // make a new Node off the books.
94 func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
96 base.Fatalf("no curfn for TempAt")
99 base.Fatalf("TempAt called with nil type")
101 if t.Kind() == types.TFUNC && t.Recv() != nil {
102 base.Fatalf("misuse of method type: %v", t)
106 Name: autotmpname(len(curfn.Dcl)),
109 n := curfn.NewLocal(pos, s, ir.PAUTO, t)
110 s.Def = n // TODO(mdempsky): Should be unnecessary.
111 n.SetEsc(ir.EscNever)
121 autotmpnamesmu sync.Mutex
122 autotmpnames []string
125 // autotmpname returns the name for an autotmp variable numbered n.
126 func autotmpname(n int) string {
127 autotmpnamesmu.Lock()
128 defer autotmpnamesmu.Unlock()
130 // Grow autotmpnames, if needed.
131 if n >= len(autotmpnames) {
132 autotmpnames = append(autotmpnames, make([]string, n+1-len(autotmpnames))...)
133 autotmpnames = autotmpnames[:cap(autotmpnames)]
138 // Give each tmp a different name so that they can be registerized.
139 // Add a preceding . to avoid clashing with legal names.
140 prefix := ".autotmp_%d"
142 s = fmt.Sprintf(prefix, n)
148 // f is method type, with receiver.
149 // return function type, receiver as first argument (or not).
150 func NewMethodType(sig *types.Type, recv *types.Type) *types.Type {
156 // TODO(mdempsky): Move this function to types.
157 // TODO(mdempsky): Preserve positions, names, and package from sig+recv.
159 params := make([]*types.Field, nrecvs+sig.NumParams())
161 params[0] = types.NewField(base.Pos, nil, recv)
163 for i, param := range sig.Params() {
164 d := types.NewField(base.Pos, nil, param.Type)
165 d.SetIsDDD(param.IsDDD())
169 results := make([]*types.Field, sig.NumResults())
170 for i, t := range sig.Results() {
171 results[i] = types.NewField(base.Pos, nil, t.Type)
174 return types.NewSignature(nil, params, results)