1 // Copyright 2011 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.
8 "cmd/compile/internal/ssa"
15 // "Portable" code generation.
17 var makefuncdatasym_nsym int32
19 func makefuncdatasym(namefmt string, funcdatakind int64) *Sym {
22 sym := Lookupf(namefmt, makefuncdatasym_nsym)
23 makefuncdatasym_nsym++
26 Nodconst(&nod, Types[TINT32], funcdatakind)
27 Thearch.Gins(obj.AFUNCDATA, &nod, pnod)
31 // gvardef inserts a VARDEF for n into the instruction stream.
32 // VARDEF is an annotation for the liveness analysis, marking a place
33 // where a complete initialization (definition) of a variable begins.
34 // Since the liveness analysis can see initialization of single-word
35 // variables quite easy, gvardef is usually only called for multi-word
36 // or 'fat' variables, those satisfying isfat(n->type).
37 // However, gvardef is also called when a non-fat variable is initialized
38 // via a block move; the only time this happens is when you have
40 // for a function with multiple return values exactly matching the return
41 // types of the current function.
43 // A 'VARDEF x' annotation in the instruction stream tells the liveness
44 // analysis to behave as though the variable x is being initialized at that
45 // point in the instruction stream. The VARDEF must appear before the
46 // actual (multi-instruction) initialization, and it must also appear after
47 // any uses of the previous value, if any. For example, if compiling:
51 // it is important to generate code like:
53 // base, len, cap = pieces of x[1:]
55 // x = {base, len, cap}
57 // If instead the generated code looked like:
60 // base, len, cap = pieces of x[1:]
61 // x = {base, len, cap}
63 // then the liveness analysis would decide the previous value of x was
64 // unnecessary even though it is about to be used by the x[1:] computation.
65 // Similarly, if the generated code looked like:
67 // base, len, cap = pieces of x[1:]
68 // x = {base, len, cap}
71 // then the liveness analysis will not preserve the new value of x, because
72 // the VARDEF appears to have "overwritten" it.
74 // VARDEF is a bit of a kludge to work around the fact that the instruction
75 // stream is working on single-word values but the liveness analysis
76 // wants to work on individual variables, which might be multi-word
77 // aggregates. It might make sense at some point to look into letting
78 // the liveness analysis work on single-word values as well, although
79 // there are complications around interface values, slices, and strings,
80 // all of which cannot be treated as individual words.
82 // VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
83 // even if its address has been taken. That is, a VARKILL annotation asserts
84 // that its argument is certainly dead, for use when the liveness analysis
85 // would not otherwise be able to deduce that fact.
87 func gvardefx(n *Node, as int) {
92 Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), n)
97 case PAUTO, PPARAM, PPARAMOUT:
98 Thearch.Gins(as, nil, n)
102 func Gvardef(n *Node) {
103 gvardefx(n, obj.AVARDEF)
106 func gvarkill(n *Node) {
107 gvardefx(n, obj.AVARKILL)
110 func removevardef(firstp *obj.Prog) {
111 for p := firstp; p != nil; p = p.Link {
112 for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL) {
115 if p.To.Type == obj.TYPE_BRANCH {
116 for p.To.Val.(*obj.Prog) != nil && (p.To.Val.(*obj.Prog).As == obj.AVARDEF || p.To.Val.(*obj.Prog).As == obj.AVARKILL) {
117 p.To.Val = p.To.Val.(*obj.Prog).Link
123 func gcsymdup(s *Sym) {
126 Fatal("cannot rosymdup %s with relocations", ls.Name)
128 ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P))
132 func emitptrargsmap() {
133 sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
135 nptr := int(Curfn.Type.Argwid / int64(Widthptr))
136 bv := bvalloc(int32(nptr) * 2)
138 if Curfn.Type.Outtuple > 0 {
141 off := duint32(sym, 0, uint32(nbitmap))
142 off = duint32(sym, off, uint32(bv.n))
144 if Curfn.Type.Thistuple > 0 {
146 onebitwalktype1(getthisx(Curfn.Type), &xoffset, bv)
149 if Curfn.Type.Intuple > 0 {
151 onebitwalktype1(getinargx(Curfn.Type), &xoffset, bv)
154 for j := 0; int32(j) < bv.n; j += 32 {
155 off = duint32(sym, off, bv.b[j/32])
157 if Curfn.Type.Outtuple > 0 {
159 onebitwalktype1(getoutargx(Curfn.Type), &xoffset, bv)
160 for j := 0; int32(j) < bv.n; j += 32 {
161 off = duint32(sym, off, bv.b[j/32])
165 ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
168 // Sort the list of stack variables. Autos after anything else,
169 // within autos, unused after used, within used, things with
170 // pointers first, zeroed things first, and then decreasing size.
171 // Because autos are laid out in decreasing addresses
172 // on the stack, pointers first, zeroed things first and decreasing size
173 // really means, in memory, things with pointers needing zeroing at
174 // the top of the stack and increasing in size.
175 // Non-autos sort on offset.
176 func cmpstackvar(a *Node, b *Node) int {
177 if a.Class != b.Class {
178 if a.Class == PAUTO {
184 if a.Class != PAUTO {
185 if a.Xoffset < b.Xoffset {
188 if a.Xoffset > b.Xoffset {
194 if a.Used != b.Used {
195 return obj.Bool2int(b.Used) - obj.Bool2int(a.Used)
198 ap := obj.Bool2int(haspointers(a.Type))
199 bp := obj.Bool2int(haspointers(b.Type))
204 ap = obj.Bool2int(a.Name.Needzero)
205 bp = obj.Bool2int(b.Name.Needzero)
210 if a.Type.Width < b.Type.Width {
213 if a.Type.Width > b.Type.Width {
217 return stringsCompare(a.Sym.Name, b.Sym.Name)
220 // stkdelta records the stack offset delta for a node
221 // during the compaction of the stack frame to remove
222 // unused stack slots.
223 var stkdelta = map[*Node]int64{}
225 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
226 func allocauto(ptxt *obj.Prog) {
230 if Curfn.Func.Dcl == nil {
234 // Mark the PAUTO's unused.
235 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
236 if ll.N.Class == PAUTO {
243 listsort(&Curfn.Func.Dcl, cmpstackvar)
245 // Unused autos are at the end, chop 'em off.
249 if n.Class == PAUTO && n.Op == ONAME && !n.Used {
250 // No locals used at all
257 for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next {
259 if n.Class == PAUTO && n.Op == ONAME && !n.Used {
261 Curfn.Func.Dcl.End = ll
266 // Reassign stack offsets of the locals that are still there.
268 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
270 if n.Class != PAUTO || n.Op != ONAME {
276 if w >= Thearch.MAXWIDTH || w < 0 {
280 Stksize = Rnd(Stksize, int64(n.Type.Align))
281 if haspointers(n.Type) {
284 if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
285 Stksize = Rnd(Stksize, int64(Widthptr))
287 if Stksize >= 1<<31 {
289 Yyerror("stack frame too large (>2GB)")
292 stkdelta[n] = -Stksize - n.Xoffset
295 Stksize = Rnd(Stksize, int64(Widthreg))
296 stkptrsize = Rnd(stkptrsize, int64(Widthreg))
300 // The debug information needs accurate offsets on the symbols.
301 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
302 if ll.N.Class != PAUTO || ll.N.Op != ONAME {
305 ll.N.Xoffset += stkdelta[ll.N]
306 delete(stkdelta, ll.N)
310 func Cgen_checknil(n *Node) {
311 if Disable_checknil != 0 {
315 // Ideally we wouldn't see any integer types here, but we do.
316 if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) {
318 Fatal("bad checknil")
321 if ((Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
323 Regalloc(®, Types[Tptr], n)
325 Thearch.Gins(obj.ACHECKNIL, ®, nil)
330 Thearch.Gins(obj.ACHECKNIL, n, nil)
333 func compile(fn *Node) {
335 Newproc = Sysfunc("newproc")
336 Deferproc = Sysfunc("deferproc")
337 Deferreturn = Sysfunc("deferreturn")
338 Panicindex = Sysfunc("panicindex")
339 panicslice = Sysfunc("panicslice")
340 throwreturn = Sysfunc("throwreturn")
360 if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
361 Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
374 // set up domain for labels
377 if Curfn.Type.Outnamed != 0 {
378 // add clearing of the output parameters
380 t := Structfirst(&save, Getoutarg(Curfn.Type))
384 n = Nod(OAS, t.Nname, nil)
386 Curfn.Nbody = concat(list1(n), Curfn.Nbody)
389 t = structnext(&save)
410 // Build an SSA backend function.
411 // TODO: get rid of usessa.
412 ssafn, usessa = buildssa(Curfn)
418 pl.Name = Linksym(Curfn.Func.Nname.Sym)
422 Nodconst(&nod1, Types[TINT32], 0)
423 nam = Curfn.Func.Nname
427 ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
428 Afunclit(&ptxt.From, Curfn.Func.Nname)
429 ptxt.From3 = new(obj.Addr)
431 ptxt.From3.Offset |= obj.DUPOK
434 ptxt.From3.Offset |= obj.WRAPPER
436 if fn.Func.Needctxt {
437 ptxt.From3.Offset |= obj.NEEDCTXT
440 ptxt.From3.Offset |= obj.NOSPLIT
442 if fn.Func.Systemstack {
443 ptxt.From.Sym.Cfunc = 1
446 // Clumsy but important.
447 // See test/recover.go for test cases and src/reflect/value.go
448 // for the actual functions being considered.
449 if myimportpath != "" && myimportpath == "reflect" {
450 if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
451 ptxt.From3.Offset |= obj.WRAPPER
457 gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
458 gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)
460 for _, t := range Curfn.Func.Fieldtrack {
464 for l := fn.Func.Dcl; l != nil; l = l.Next {
466 if n.Op != ONAME { // might be OTYPE or OLITERAL
470 case PAUTO, PPARAM, PPARAMOUT:
471 Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width)
472 p = Thearch.Gins(obj.ATYPE, l.N, &nod1)
473 p.From.Gotype = Linksym(ngotype(l.N))
477 if ssafn != nil && usessa {
478 genssa(ssafn, ptxt, gcargs, gclocals)
481 Genlist(Curfn.Func.Enter)
488 if Curfn.Func.Endlineno != 0 {
489 lineno = Curfn.Func.Endlineno
492 if Curfn.Type.Outtuple != 0 {
493 Ginscall(throwreturn, 0)
498 // TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
502 // deferreturn pretends to have one uintptr argument.
503 // Reserve space for it so stack scanner is happy.
504 if Maxarg < int64(Widthptr) {
505 Maxarg = int64(Widthptr)
514 Pc.As = obj.ARET // overwrite AEND
518 if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
523 Thearch.Expandchecks(ptxt)
529 fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize))
533 if int64(Stksize)+Maxarg > 1<<31 {
534 Yyerror("stack frame too large (>2GB)")
538 // Emit garbage collection symbols.
539 liveness(Curfn, ptxt, gcargs, gclocals)
544 Thearch.Defframe(ptxt)
550 // Remove leftover instrumentation from the instruction stream.