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