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 Fatalf("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 // cmpstackvarlt reports whether the stack variable a sorts before b.
170 // Sort the list of stack variables. Autos after anything else,
171 // within autos, unused after used, within used, things with
172 // pointers first, zeroed things first, and then decreasing size.
173 // Because autos are laid out in decreasing addresses
174 // on the stack, pointers first, zeroed things first and decreasing size
175 // really means, in memory, things with pointers needing zeroing at
176 // the top of the stack and increasing in size.
177 // Non-autos sort on offset.
178 func cmpstackvarlt(a, b *Node) bool {
179 if a.Class != b.Class {
180 if a.Class == PAUTO {
186 if a.Class != PAUTO {
187 if a.Xoffset < b.Xoffset {
190 if a.Xoffset > b.Xoffset {
196 if a.Used != b.Used {
200 ap := haspointers(a.Type)
201 bp := haspointers(b.Type)
212 if a.Type.Width < b.Type.Width {
215 if a.Type.Width > b.Type.Width {
219 return a.Sym.Name < b.Sym.Name
222 // stkdelta records the stack offset delta for a node
223 // during the compaction of the stack frame to remove
224 // unused stack slots.
225 var stkdelta = map[*Node]int64{}
227 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
228 func allocauto(ptxt *obj.Prog) {
232 if Curfn.Func.Dcl == nil {
236 // Mark the PAUTO's unused.
237 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
238 if ll.N.Class == PAUTO {
245 listsort(&Curfn.Func.Dcl, cmpstackvarlt)
247 // Unused autos are at the end, chop 'em off.
251 if n.Class == PAUTO && n.Op == ONAME && !n.Used {
252 // No locals used at all
259 for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next {
261 if n.Class == PAUTO && n.Op == ONAME && !n.Used {
263 Curfn.Func.Dcl.End = ll
268 // Reassign stack offsets of the locals that are still there.
270 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
272 if n.Class != PAUTO || n.Op != ONAME {
278 if w >= Thearch.MAXWIDTH || w < 0 {
282 Stksize = Rnd(Stksize, int64(n.Type.Align))
283 if haspointers(n.Type) {
286 if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
287 Stksize = Rnd(Stksize, int64(Widthptr))
289 if Stksize >= 1<<31 {
291 Yyerror("stack frame too large (>2GB)")
294 stkdelta[n] = -Stksize - n.Xoffset
297 Stksize = Rnd(Stksize, int64(Widthreg))
298 stkptrsize = Rnd(stkptrsize, int64(Widthreg))
302 // The debug information needs accurate offsets on the symbols.
303 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
304 if ll.N.Class != PAUTO || ll.N.Op != ONAME {
307 ll.N.Xoffset += stkdelta[ll.N]
308 delete(stkdelta, ll.N)
312 func Cgen_checknil(n *Node) {
313 if Disable_checknil != 0 {
317 // Ideally we wouldn't see any integer types here, but we do.
318 if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) {
320 Fatalf("bad checknil")
323 if ((Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
325 Regalloc(®, Types[Tptr], n)
327 Thearch.Gins(obj.ACHECKNIL, ®, nil)
332 Thearch.Gins(obj.ACHECKNIL, n, nil)
335 func compile(fn *Node) {
337 Newproc = Sysfunc("newproc")
338 Deferproc = Sysfunc("deferproc")
339 Deferreturn = Sysfunc("deferreturn")
340 Panicindex = Sysfunc("panicindex")
341 panicslice = Sysfunc("panicslice")
342 throwreturn = Sysfunc("throwreturn")
343 growslice = Sysfunc("growslice")
344 typedmemmove_nostore = Sysfunc("typedmemmove_nostore")
345 panicdottype = Sysfunc("panicdottype")
365 if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
366 Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
379 // set up domain for labels
382 if Curfn.Type.Outnamed {
383 // add clearing of the output parameters
385 t := Structfirst(&save, Getoutarg(Curfn.Type))
389 n = Nod(OAS, t.Nname, nil)
391 Curfn.Nbody = concat(list1(n), Curfn.Nbody)
394 t = structnext(&save)
415 // Build an SSA backend function.
416 // TODO: get rid of usessa.
417 ssafn, usessa = buildssa(Curfn)
423 pl.Name = Linksym(Curfn.Func.Nname.Sym)
427 Nodconst(&nod1, Types[TINT32], 0)
428 nam = Curfn.Func.Nname
432 ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
433 Afunclit(&ptxt.From, Curfn.Func.Nname)
434 ptxt.From3 = new(obj.Addr)
436 ptxt.From3.Offset |= obj.DUPOK
439 ptxt.From3.Offset |= obj.WRAPPER
441 if fn.Func.Needctxt {
442 ptxt.From3.Offset |= obj.NEEDCTXT
445 ptxt.From3.Offset |= obj.NOSPLIT
447 if fn.Func.Systemstack {
448 ptxt.From.Sym.Cfunc = 1
451 // Clumsy but important.
452 // See test/recover.go for test cases and src/reflect/value.go
453 // for the actual functions being considered.
454 if myimportpath != "" && myimportpath == "reflect" {
455 if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
456 ptxt.From3.Offset |= obj.WRAPPER
462 gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
463 gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)
465 for _, t := range Curfn.Func.Fieldtrack {
469 for l := fn.Func.Dcl; l != nil; l = l.Next {
471 if n.Op != ONAME { // might be OTYPE or OLITERAL
475 case PAUTO, PPARAM, PPARAMOUT:
476 Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width)
477 p = Thearch.Gins(obj.ATYPE, l.N, &nod1)
478 p.From.Gotype = Linksym(ngotype(l.N))
482 if ssafn != nil && usessa {
483 genssa(ssafn, ptxt, gcargs, gclocals)
486 Genlist(Curfn.Func.Enter)
493 if Curfn.Func.Endlineno != 0 {
494 lineno = Curfn.Func.Endlineno
497 if Curfn.Type.Outtuple != 0 {
498 Ginscall(throwreturn, 0)
503 // TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
507 // deferreturn pretends to have one uintptr argument.
508 // Reserve space for it so stack scanner is happy.
509 if Maxarg < int64(Widthptr) {
510 Maxarg = int64(Widthptr)
519 Pc.As = obj.ARET // overwrite AEND
523 if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
528 Thearch.Expandchecks(ptxt)
534 fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize))
538 if int64(Stksize)+Maxarg > 1<<31 {
539 Yyerror("stack frame too large (>2GB)")
543 // Emit garbage collection symbols.
544 liveness(Curfn, ptxt, gcargs, gclocals)
549 Thearch.Defframe(ptxt)
555 // Remove leftover instrumentation from the instruction stream.