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.
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 if as == obj.AVARLIVE {
99 Thearch.Gins(as, n, nil)
101 Thearch.Gins(as, nil, n)
106 func Gvardef(n *Node) {
107 gvardefx(n, obj.AVARDEF)
110 func gvarkill(n *Node) {
111 gvardefx(n, obj.AVARKILL)
114 func gvarlive(n *Node) {
115 gvardefx(n, obj.AVARLIVE)
118 func removevardef(firstp *obj.Prog) {
119 for p := firstp; p != nil; p = p.Link {
120 for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL || p.Link.As == obj.AVARLIVE) {
123 if p.To.Type == obj.TYPE_BRANCH {
124 for p.To.Val.(*obj.Prog) != nil && (p.To.Val.(*obj.Prog).As == obj.AVARDEF || p.To.Val.(*obj.Prog).As == obj.AVARKILL || p.To.Val.(*obj.Prog).As == obj.AVARLIVE) {
125 p.To.Val = p.To.Val.(*obj.Prog).Link
131 func gcsymdup(s *Sym) {
134 Fatalf("cannot rosymdup %s with relocations", ls.Name)
136 ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P))
140 func emitptrargsmap() {
141 if Curfn.Func.Nname.Sym.Name == "_" {
144 sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
146 nptr := int(Curfn.Type.Argwid / int64(Widthptr))
147 bv := bvalloc(int32(nptr) * 2)
149 if Curfn.Type.Outtuple > 0 {
152 off := duint32(sym, 0, uint32(nbitmap))
153 off = duint32(sym, off, uint32(bv.n))
155 if Curfn.Type.Thistuple > 0 {
157 onebitwalktype1(getthisx(Curfn.Type), &xoffset, bv)
160 if Curfn.Type.Intuple > 0 {
162 onebitwalktype1(getinargx(Curfn.Type), &xoffset, bv)
165 for j := 0; int32(j) < bv.n; j += 32 {
166 off = duint32(sym, off, bv.b[j/32])
168 if Curfn.Type.Outtuple > 0 {
170 onebitwalktype1(getoutargx(Curfn.Type), &xoffset, bv)
171 for j := 0; int32(j) < bv.n; j += 32 {
172 off = duint32(sym, off, bv.b[j/32])
176 ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
179 // cmpstackvarlt reports whether the stack variable a sorts before b.
181 // Sort the list of stack variables. Autos after anything else,
182 // within autos, unused after used, within used, things with
183 // pointers first, zeroed things first, and then decreasing size.
184 // Because autos are laid out in decreasing addresses
185 // on the stack, pointers first, zeroed things first and decreasing size
186 // really means, in memory, things with pointers needing zeroing at
187 // the top of the stack and increasing in size.
188 // Non-autos sort on offset.
189 func cmpstackvarlt(a, b *Node) bool {
190 if (a.Class == PAUTO) != (b.Class == PAUTO) {
191 return b.Class == PAUTO
194 if a.Class != PAUTO {
195 return a.Xoffset < b.Xoffset
198 if a.Used != b.Used {
202 ap := haspointers(a.Type)
203 bp := haspointers(b.Type)
214 if a.Type.Width != b.Type.Width {
215 return a.Type.Width > b.Type.Width
218 return a.Sym.Name < b.Sym.Name
221 // byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
222 type byStackVar []*Node
224 func (s byStackVar) Len() int { return len(s) }
225 func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
226 func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
228 // stkdelta records the stack offset delta for a node
229 // during the compaction of the stack frame to remove
230 // unused stack slots.
231 var stkdelta = map[*Node]int64{}
233 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
234 func allocauto(ptxt *obj.Prog) {
238 if len(Curfn.Func.Dcl) == 0 {
242 // Mark the PAUTO's unused.
243 for _, ln := range Curfn.Func.Dcl {
244 if ln.Class == PAUTO {
251 sort.Sort(byStackVar(Curfn.Func.Dcl))
253 // Unused autos are at the end, chop 'em off.
254 n := Curfn.Func.Dcl[0]
255 if n.Class == PAUTO && n.Op == ONAME && !n.Used {
256 // No locals used at all
263 for i := 1; i < len(Curfn.Func.Dcl); i++ {
264 n = Curfn.Func.Dcl[i]
265 if n.Class == PAUTO && n.Op == ONAME && !n.Used {
266 Curfn.Func.Dcl = Curfn.Func.Dcl[:i]
271 // Reassign stack offsets of the locals that are still there.
273 for _, n := range Curfn.Func.Dcl {
274 if n.Class != PAUTO || n.Op != ONAME {
280 if w >= Thearch.MAXWIDTH || w < 0 {
284 Stksize = Rnd(Stksize, int64(n.Type.Align))
285 if haspointers(n.Type) {
288 if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
289 Stksize = Rnd(Stksize, int64(Widthptr))
291 if Stksize >= 1<<31 {
293 Yyerror("stack frame too large (>2GB)")
296 stkdelta[n] = -Stksize - n.Xoffset
299 Stksize = Rnd(Stksize, int64(Widthreg))
300 stkptrsize = Rnd(stkptrsize, int64(Widthreg))
304 // The debug information needs accurate offsets on the symbols.
305 for _, ln := range Curfn.Func.Dcl {
306 if ln.Class != PAUTO || ln.Op != ONAME {
309 ln.Xoffset += stkdelta[ln]
314 func Cgen_checknil(n *Node) {
315 if Disable_checknil != 0 {
319 // Ideally we wouldn't see any integer types here, but we do.
320 if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) {
322 Fatalf("bad checknil")
325 if ((Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
327 Regalloc(®, Types[Tptr], n)
329 Thearch.Gins(obj.ACHECKNIL, ®, nil)
334 Thearch.Gins(obj.ACHECKNIL, n, nil)
337 func compile(fn *Node) {
339 Newproc = Sysfunc("newproc")
340 Deferproc = Sysfunc("deferproc")
341 Deferreturn = Sysfunc("deferreturn")
342 Panicindex = Sysfunc("panicindex")
343 panicslice = Sysfunc("panicslice")
344 throwreturn = Sysfunc("throwreturn")
362 if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
363 Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
376 // set up domain for labels
379 if Curfn.Type.Outnamed {
380 // add clearing of the output parameters
382 t := Structfirst(&save, Getoutarg(Curfn.Type))
386 n = Nod(OAS, t.Nname, nil)
388 Curfn.Nbody = concat(list1(n), Curfn.Nbody)
391 t = structnext(&save)
416 pl.Name = Linksym(Curfn.Func.Nname.Sym)
420 Nodconst(&nod1, Types[TINT32], 0)
421 nam = Curfn.Func.Nname
425 ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
426 Afunclit(&ptxt.From, Curfn.Func.Nname)
427 ptxt.From3 = new(obj.Addr)
429 ptxt.From3.Offset |= obj.DUPOK
432 ptxt.From3.Offset |= obj.WRAPPER
434 if fn.Func.Needctxt {
435 ptxt.From3.Offset |= obj.NEEDCTXT
437 if fn.Func.Pragma&Nosplit != 0 {
438 ptxt.From3.Offset |= obj.NOSPLIT
440 if fn.Func.Pragma&Systemstack != 0 {
441 ptxt.From.Sym.Cfunc = 1
444 // Clumsy but important.
445 // See test/recover.go for test cases and src/reflect/value.go
446 // for the actual functions being considered.
447 if myimportpath != "" && myimportpath == "reflect" {
448 if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
449 ptxt.From3.Offset |= obj.WRAPPER
455 gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
456 gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)
458 for _, t := range Curfn.Func.Fieldtrack {
462 for _, n := range fn.Func.Dcl {
463 if n.Op != ONAME { // might be OTYPE or OLITERAL
467 case PAUTO, PPARAM, PPARAMOUT:
468 Nodconst(&nod1, Types[TUINTPTR], n.Type.Width)
469 p = Thearch.Gins(obj.ATYPE, n, &nod1)
470 p.From.Gotype = Linksym(ngotype(n))
474 Genslice(Curfn.Func.Enter.Slice())
481 if Curfn.Func.Endlineno != 0 {
482 lineno = Curfn.Func.Endlineno
485 if Curfn.Type.Outtuple != 0 {
486 Ginscall(throwreturn, 0)
491 // TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
495 // deferreturn pretends to have one uintptr argument.
496 // Reserve space for it so stack scanner is happy.
497 if Maxarg < int64(Widthptr) {
498 Maxarg = int64(Widthptr)
507 Pc.As = obj.ARET // overwrite AEND
511 if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
516 Thearch.Expandchecks(ptxt)
522 fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize))
526 if int64(Stksize)+Maxarg > 1<<31 {
527 Yyerror("stack frame too large (>2GB)")
531 // Emit garbage collection symbols.
532 liveness(Curfn, ptxt, gcargs, gclocals)
537 Thearch.Defframe(ptxt)
543 // Remove leftover instrumentation from the instruction stream.