github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/gc/pgen.go (about)

     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.
     4  
     5  package gc
     6  
     7  import (
     8  	"cmd/compile/internal/ssa"
     9  	"cmd/internal/obj"
    10  	"crypto/md5"
    11  	"fmt"
    12  	"sort"
    13  	"strings"
    14  )
    15  
    16  // "Portable" code generation.
    17  
    18  var makefuncdatasym_nsym int
    19  
    20  func makefuncdatasym(nameprefix string, funcdatakind int64) *Sym {
    21  	var nod Node
    22  
    23  	sym := LookupN(nameprefix, makefuncdatasym_nsym)
    24  	makefuncdatasym_nsym++
    25  	pnod := newname(sym)
    26  	pnod.Class = PEXTERN
    27  	Nodconst(&nod, Types[TINT32], funcdatakind)
    28  	Thearch.Gins(obj.AFUNCDATA, &nod, pnod)
    29  	return sym
    30  }
    31  
    32  // gvardef inserts a VARDEF for n into the instruction stream.
    33  // VARDEF is an annotation for the liveness analysis, marking a place
    34  // where a complete initialization (definition) of a variable begins.
    35  // Since the liveness analysis can see initialization of single-word
    36  // variables quite easy, gvardef is usually only called for multi-word
    37  // or 'fat' variables, those satisfying isfat(n->type).
    38  // However, gvardef is also called when a non-fat variable is initialized
    39  // via a block move; the only time this happens is when you have
    40  //	return f()
    41  // for a function with multiple return values exactly matching the return
    42  // types of the current function.
    43  //
    44  // A 'VARDEF x' annotation in the instruction stream tells the liveness
    45  // analysis to behave as though the variable x is being initialized at that
    46  // point in the instruction stream. The VARDEF must appear before the
    47  // actual (multi-instruction) initialization, and it must also appear after
    48  // any uses of the previous value, if any. For example, if compiling:
    49  //
    50  //	x = x[1:]
    51  //
    52  // it is important to generate code like:
    53  //
    54  //	base, len, cap = pieces of x[1:]
    55  //	VARDEF x
    56  //	x = {base, len, cap}
    57  //
    58  // If instead the generated code looked like:
    59  //
    60  //	VARDEF x
    61  //	base, len, cap = pieces of x[1:]
    62  //	x = {base, len, cap}
    63  //
    64  // then the liveness analysis would decide the previous value of x was
    65  // unnecessary even though it is about to be used by the x[1:] computation.
    66  // Similarly, if the generated code looked like:
    67  //
    68  //	base, len, cap = pieces of x[1:]
    69  //	x = {base, len, cap}
    70  //	VARDEF x
    71  //
    72  // then the liveness analysis will not preserve the new value of x, because
    73  // the VARDEF appears to have "overwritten" it.
    74  //
    75  // VARDEF is a bit of a kludge to work around the fact that the instruction
    76  // stream is working on single-word values but the liveness analysis
    77  // wants to work on individual variables, which might be multi-word
    78  // aggregates. It might make sense at some point to look into letting
    79  // the liveness analysis work on single-word values as well, although
    80  // there are complications around interface values, slices, and strings,
    81  // all of which cannot be treated as individual words.
    82  //
    83  // VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
    84  // even if its address has been taken. That is, a VARKILL annotation asserts
    85  // that its argument is certainly dead, for use when the liveness analysis
    86  // would not otherwise be able to deduce that fact.
    87  
    88  func gvardefx(n *Node, as obj.As) {
    89  	if n == nil {
    90  		Fatalf("gvardef nil")
    91  	}
    92  	if n.Op != ONAME {
    93  		Yyerror("gvardef %v; %v", Oconv(n.Op, FmtSharp), n)
    94  		return
    95  	}
    96  
    97  	switch n.Class {
    98  	case PAUTO, PPARAM, PPARAMOUT:
    99  		if as == obj.AVARLIVE {
   100  			Thearch.Gins(as, n, nil)
   101  		} else {
   102  			Thearch.Gins(as, nil, n)
   103  		}
   104  	}
   105  }
   106  
   107  func Gvardef(n *Node) {
   108  	gvardefx(n, obj.AVARDEF)
   109  }
   110  
   111  func Gvarkill(n *Node) {
   112  	gvardefx(n, obj.AVARKILL)
   113  }
   114  
   115  func Gvarlive(n *Node) {
   116  	gvardefx(n, obj.AVARLIVE)
   117  }
   118  
   119  func removevardef(firstp *obj.Prog) {
   120  	for p := firstp; p != nil; p = p.Link {
   121  		for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL || p.Link.As == obj.AVARLIVE) {
   122  			p.Link = p.Link.Link
   123  		}
   124  		if p.To.Type == obj.TYPE_BRANCH {
   125  			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) {
   126  				p.To.Val = p.To.Val.(*obj.Prog).Link
   127  			}
   128  		}
   129  	}
   130  }
   131  
   132  func gcsymdup(s *Sym) {
   133  	ls := Linksym(s)
   134  	if len(ls.R) > 0 {
   135  		Fatalf("cannot rosymdup %s with relocations", ls.Name)
   136  	}
   137  	ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P))
   138  	ls.Dupok = true
   139  }
   140  
   141  func emitptrargsmap() {
   142  	if Curfn.Func.Nname.Sym.Name == "_" {
   143  		return
   144  	}
   145  	sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
   146  
   147  	nptr := int(Curfn.Type.ArgWidth() / int64(Widthptr))
   148  	bv := bvalloc(int32(nptr) * 2)
   149  	nbitmap := 1
   150  	if Curfn.Type.Results().NumFields() > 0 {
   151  		nbitmap = 2
   152  	}
   153  	off := duint32(sym, 0, uint32(nbitmap))
   154  	off = duint32(sym, off, uint32(bv.n))
   155  	var xoffset int64
   156  	if Curfn.Type.Recv() != nil {
   157  		xoffset = 0
   158  		onebitwalktype1(Curfn.Type.Recvs(), &xoffset, bv)
   159  	}
   160  
   161  	if Curfn.Type.Params().NumFields() > 0 {
   162  		xoffset = 0
   163  		onebitwalktype1(Curfn.Type.Params(), &xoffset, bv)
   164  	}
   165  
   166  	for j := 0; int32(j) < bv.n; j += 32 {
   167  		off = duint32(sym, off, bv.b[j/32])
   168  	}
   169  	if Curfn.Type.Results().NumFields() > 0 {
   170  		xoffset = 0
   171  		onebitwalktype1(Curfn.Type.Results(), &xoffset, bv)
   172  		for j := 0; int32(j) < bv.n; j += 32 {
   173  			off = duint32(sym, off, bv.b[j/32])
   174  		}
   175  	}
   176  
   177  	ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
   178  }
   179  
   180  // cmpstackvarlt reports whether the stack variable a sorts before b.
   181  //
   182  // Sort the list of stack variables. Autos after anything else,
   183  // within autos, unused after used, within used, things with
   184  // pointers first, zeroed things first, and then decreasing size.
   185  // Because autos are laid out in decreasing addresses
   186  // on the stack, pointers first, zeroed things first and decreasing size
   187  // really means, in memory, things with pointers needing zeroing at
   188  // the top of the stack and increasing in size.
   189  // Non-autos sort on offset.
   190  func cmpstackvarlt(a, b *Node) bool {
   191  	if (a.Class == PAUTO) != (b.Class == PAUTO) {
   192  		return b.Class == PAUTO
   193  	}
   194  
   195  	if a.Class != PAUTO {
   196  		return a.Xoffset < b.Xoffset
   197  	}
   198  
   199  	if a.Used != b.Used {
   200  		return a.Used
   201  	}
   202  
   203  	ap := haspointers(a.Type)
   204  	bp := haspointers(b.Type)
   205  	if ap != bp {
   206  		return ap
   207  	}
   208  
   209  	ap = a.Name.Needzero
   210  	bp = b.Name.Needzero
   211  	if ap != bp {
   212  		return ap
   213  	}
   214  
   215  	if a.Type.Width != b.Type.Width {
   216  		return a.Type.Width > b.Type.Width
   217  	}
   218  
   219  	return a.Sym.Name < b.Sym.Name
   220  }
   221  
   222  // byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
   223  type byStackVar []*Node
   224  
   225  func (s byStackVar) Len() int           { return len(s) }
   226  func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
   227  func (s byStackVar) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   228  
   229  // stkdelta records the stack offset delta for a node
   230  // during the compaction of the stack frame to remove
   231  // unused stack slots.
   232  var stkdelta = map[*Node]int64{}
   233  
   234  // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
   235  func allocauto(ptxt *obj.Prog) {
   236  	Stksize = 0
   237  	stkptrsize = 0
   238  
   239  	if len(Curfn.Func.Dcl) == 0 {
   240  		return
   241  	}
   242  
   243  	// Mark the PAUTO's unused.
   244  	for _, ln := range Curfn.Func.Dcl {
   245  		if ln.Class == PAUTO {
   246  			ln.Used = false
   247  		}
   248  	}
   249  
   250  	markautoused(ptxt)
   251  
   252  	sort.Sort(byStackVar(Curfn.Func.Dcl))
   253  
   254  	// Unused autos are at the end, chop 'em off.
   255  	n := Curfn.Func.Dcl[0]
   256  	if n.Class == PAUTO && n.Op == ONAME && !n.Used {
   257  		// No locals used at all
   258  		Curfn.Func.Dcl = nil
   259  
   260  		fixautoused(ptxt)
   261  		return
   262  	}
   263  
   264  	for i := 1; i < len(Curfn.Func.Dcl); i++ {
   265  		n = Curfn.Func.Dcl[i]
   266  		if n.Class == PAUTO && n.Op == ONAME && !n.Used {
   267  			Curfn.Func.Dcl = Curfn.Func.Dcl[:i]
   268  			break
   269  		}
   270  	}
   271  
   272  	// Reassign stack offsets of the locals that are still there.
   273  	var w int64
   274  	for _, n := range Curfn.Func.Dcl {
   275  		if n.Class != PAUTO || n.Op != ONAME {
   276  			continue
   277  		}
   278  
   279  		dowidth(n.Type)
   280  		w = n.Type.Width
   281  		if w >= Thearch.MAXWIDTH || w < 0 {
   282  			Fatalf("bad width")
   283  		}
   284  		Stksize += w
   285  		Stksize = Rnd(Stksize, int64(n.Type.Align))
   286  		if haspointers(n.Type) {
   287  			stkptrsize = Stksize
   288  		}
   289  		if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
   290  			Stksize = Rnd(Stksize, int64(Widthptr))
   291  		}
   292  		if Stksize >= 1<<31 {
   293  			setlineno(Curfn)
   294  			Yyerror("stack frame too large (>2GB)")
   295  		}
   296  
   297  		stkdelta[n] = -Stksize - n.Xoffset
   298  	}
   299  
   300  	Stksize = Rnd(Stksize, int64(Widthreg))
   301  	stkptrsize = Rnd(stkptrsize, int64(Widthreg))
   302  
   303  	fixautoused(ptxt)
   304  
   305  	// The debug information needs accurate offsets on the symbols.
   306  	for _, ln := range Curfn.Func.Dcl {
   307  		if ln.Class != PAUTO || ln.Op != ONAME {
   308  			continue
   309  		}
   310  		ln.Xoffset += stkdelta[ln]
   311  		delete(stkdelta, ln)
   312  	}
   313  }
   314  
   315  func Cgen_checknil(n *Node) {
   316  	if Disable_checknil != 0 {
   317  		return
   318  	}
   319  
   320  	// Ideally we wouldn't see any integer types here, but we do.
   321  	if n.Type == nil || (!n.Type.IsPtr() && !n.Type.IsInteger() && n.Type.Etype != TUNSAFEPTR) {
   322  		Dump("checknil", n)
   323  		Fatalf("bad checknil")
   324  	}
   325  
   326  	if ((Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
   327  		var reg Node
   328  		Regalloc(&reg, Types[Tptr], n)
   329  		Cgen(n, &reg)
   330  		Thearch.Gins(obj.ACHECKNIL, &reg, nil)
   331  		Regfree(&reg)
   332  		return
   333  	}
   334  
   335  	Thearch.Gins(obj.ACHECKNIL, n, nil)
   336  }
   337  
   338  func compile(fn *Node) {
   339  	if Newproc == nil {
   340  		Newproc = Sysfunc("newproc")
   341  		Deferproc = Sysfunc("deferproc")
   342  		Deferreturn = Sysfunc("deferreturn")
   343  		Panicindex = Sysfunc("panicindex")
   344  		panicslice = Sysfunc("panicslice")
   345  		panicdivide = Sysfunc("panicdivide")
   346  		throwreturn = Sysfunc("throwreturn")
   347  		growslice = Sysfunc("growslice")
   348  		writebarrierptr = Sysfunc("writebarrierptr")
   349  		typedmemmove = Sysfunc("typedmemmove")
   350  		panicdottype = Sysfunc("panicdottype")
   351  	}
   352  
   353  	defer func(lno int32) {
   354  		lineno = lno
   355  	}(setlineno(fn))
   356  
   357  	Curfn = fn
   358  	dowidth(Curfn.Type)
   359  
   360  	if len(fn.Nbody.Slice()) == 0 {
   361  		if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
   362  			Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
   363  			return
   364  		}
   365  
   366  		if Debug['A'] != 0 {
   367  			return
   368  		}
   369  		emitptrargsmap()
   370  		return
   371  	}
   372  
   373  	saveerrors()
   374  
   375  	// set up domain for labels
   376  	clearlabels()
   377  
   378  	if Curfn.Type.Outnamed {
   379  		// add clearing of the output parameters
   380  		for _, t := range Curfn.Type.Results().Fields().Slice() {
   381  			if t.Nname != nil {
   382  				n := Nod(OAS, t.Nname, nil)
   383  				n = typecheck(n, Etop)
   384  				Curfn.Nbody.Set(append([]*Node{n}, Curfn.Nbody.Slice()...))
   385  			}
   386  		}
   387  	}
   388  
   389  	order(Curfn)
   390  	if nerrors != 0 {
   391  		return
   392  	}
   393  
   394  	hasdefer = false
   395  	walk(Curfn)
   396  	if nerrors != 0 {
   397  		return
   398  	}
   399  	if instrumenting {
   400  		instrument(Curfn)
   401  	}
   402  	if nerrors != 0 {
   403  		return
   404  	}
   405  
   406  	// Build an SSA backend function.
   407  	var ssafn *ssa.Func
   408  	if shouldssa(Curfn) {
   409  		ssafn = buildssa(Curfn)
   410  	}
   411  
   412  	continpc = nil
   413  	breakpc = nil
   414  
   415  	pl := newplist()
   416  	pl.Name = Linksym(Curfn.Func.Nname.Sym)
   417  
   418  	setlineno(Curfn)
   419  
   420  	var nod1 Node
   421  	Nodconst(&nod1, Types[TINT32], 0)
   422  	nam := Curfn.Func.Nname
   423  	if isblank(nam) {
   424  		nam = nil
   425  	}
   426  	ptxt := Thearch.Gins(obj.ATEXT, nam, &nod1)
   427  	Afunclit(&ptxt.From, Curfn.Func.Nname)
   428  	ptxt.From3 = new(obj.Addr)
   429  	if fn.Func.Dupok {
   430  		ptxt.From3.Offset |= obj.DUPOK
   431  	}
   432  	if fn.Func.Wrapper {
   433  		ptxt.From3.Offset |= obj.WRAPPER
   434  	}
   435  	if fn.Func.Needctxt {
   436  		ptxt.From3.Offset |= obj.NEEDCTXT
   437  	}
   438  	if fn.Func.Pragma&Nosplit != 0 {
   439  		ptxt.From3.Offset |= obj.NOSPLIT
   440  	}
   441  	if fn.Func.ReflectMethod {
   442  		ptxt.From3.Offset |= obj.REFLECTMETHOD
   443  	}
   444  	if fn.Func.Pragma&Systemstack != 0 {
   445  		ptxt.From.Sym.Cfunc = true
   446  	}
   447  
   448  	// Clumsy but important.
   449  	// See test/recover.go for test cases and src/reflect/value.go
   450  	// for the actual functions being considered.
   451  	if myimportpath == "reflect" {
   452  		if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
   453  			ptxt.From3.Offset |= obj.WRAPPER
   454  		}
   455  	}
   456  
   457  	ginit()
   458  
   459  	gcargs := makefuncdatasym("gcargs·", obj.FUNCDATA_ArgsPointerMaps)
   460  	gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps)
   461  
   462  	if obj.Fieldtrack_enabled != 0 && len(Curfn.Func.FieldTrack) > 0 {
   463  		trackSyms := make([]*Sym, 0, len(Curfn.Func.FieldTrack))
   464  		for sym := range Curfn.Func.FieldTrack {
   465  			trackSyms = append(trackSyms, sym)
   466  		}
   467  		sort.Sort(symByName(trackSyms))
   468  		for _, sym := range trackSyms {
   469  			gtrack(sym)
   470  		}
   471  	}
   472  
   473  	for _, n := range fn.Func.Dcl {
   474  		if n.Op != ONAME { // might be OTYPE or OLITERAL
   475  			continue
   476  		}
   477  		switch n.Class {
   478  		case PAUTO, PPARAM, PPARAMOUT:
   479  			Nodconst(&nod1, Types[TUINTPTR], n.Type.Width)
   480  			p := Thearch.Gins(obj.ATYPE, n, &nod1)
   481  			p.From.Gotype = Linksym(ngotype(n))
   482  		}
   483  	}
   484  
   485  	if ssafn != nil {
   486  		genssa(ssafn, ptxt, gcargs, gclocals)
   487  		ssafn.Free()
   488  	} else {
   489  		genlegacy(ptxt, gcargs, gclocals)
   490  	}
   491  }
   492  
   493  type symByName []*Sym
   494  
   495  func (a symByName) Len() int           { return len(a) }
   496  func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
   497  func (a symByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   498  
   499  // genlegacy compiles Curfn using the legacy non-SSA code generator.
   500  func genlegacy(ptxt *obj.Prog, gcargs, gclocals *Sym) {
   501  	Genlist(Curfn.Func.Enter)
   502  	Genlist(Curfn.Nbody)
   503  	gclean()
   504  	checklabels()
   505  	if nerrors != 0 {
   506  		return
   507  	}
   508  	if Curfn.Func.Endlineno != 0 {
   509  		lineno = Curfn.Func.Endlineno
   510  	}
   511  
   512  	if Curfn.Type.Results().NumFields() != 0 {
   513  		Ginscall(throwreturn, 0)
   514  	}
   515  
   516  	ginit()
   517  
   518  	// TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
   519  	cgen_ret(nil)
   520  
   521  	if hasdefer {
   522  		// deferreturn pretends to have one uintptr argument.
   523  		// Reserve space for it so stack scanner is happy.
   524  		if Maxarg < int64(Widthptr) {
   525  			Maxarg = int64(Widthptr)
   526  		}
   527  	}
   528  
   529  	gclean()
   530  	if nerrors != 0 {
   531  		return
   532  	}
   533  
   534  	Pc.As = obj.ARET // overwrite AEND
   535  	Pc.Lineno = lineno
   536  
   537  	fixjmp(ptxt)
   538  	if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
   539  		regopt(ptxt)
   540  		nilopt(ptxt)
   541  	}
   542  
   543  	Thearch.Expandchecks(ptxt)
   544  
   545  	allocauto(ptxt)
   546  
   547  	setlineno(Curfn)
   548  	if Stksize+Maxarg > 1<<31 {
   549  		Yyerror("stack frame too large (>2GB)")
   550  		return
   551  	}
   552  
   553  	// Emit garbage collection symbols.
   554  	liveness(Curfn, ptxt, gcargs, gclocals)
   555  
   556  	gcsymdup(gcargs)
   557  	gcsymdup(gclocals)
   558  
   559  	Thearch.Defframe(ptxt)
   560  
   561  	if Debug['f'] != 0 {
   562  		frame(0)
   563  	}
   564  
   565  	// Remove leftover instrumentation from the instruction stream.
   566  	removevardef(ptxt)
   567  }