github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/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  	"cmd/internal/src"
    11  	"cmd/internal/sys"
    12  	"fmt"
    13  	"sort"
    14  	"strings"
    15  )
    16  
    17  // "Portable" code generation.
    18  
    19  var makefuncdatasym_nsym int
    20  
    21  func makefuncdatasym(nameprefix string, funcdatakind int64) *Sym {
    22  	sym := lookupN(nameprefix, makefuncdatasym_nsym)
    23  	makefuncdatasym_nsym++
    24  	pnod := newname(sym)
    25  	pnod.Class = PEXTERN
    26  	p := Gins(obj.AFUNCDATA, nil, pnod)
    27  	Addrconst(&p.From, funcdatakind)
    28  	return sym
    29  }
    30  
    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
    39  //	return f()
    40  // for a function with multiple return values exactly matching the return
    41  // types of the current function.
    42  //
    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:
    48  //
    49  //	x = x[1:]
    50  //
    51  // it is important to generate code like:
    52  //
    53  //	base, len, cap = pieces of x[1:]
    54  //	VARDEF x
    55  //	x = {base, len, cap}
    56  //
    57  // If instead the generated code looked like:
    58  //
    59  //	VARDEF x
    60  //	base, len, cap = pieces of x[1:]
    61  //	x = {base, len, cap}
    62  //
    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:
    66  //
    67  //	base, len, cap = pieces of x[1:]
    68  //	x = {base, len, cap}
    69  //	VARDEF x
    70  //
    71  // then the liveness analysis will not preserve the new value of x, because
    72  // the VARDEF appears to have "overwritten" it.
    73  //
    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.
    81  //
    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.
    86  
    87  func gvardefx(n *Node, as obj.As) {
    88  	if n == nil {
    89  		Fatalf("gvardef nil")
    90  	}
    91  	if n.Op != ONAME {
    92  		yyerror("gvardef %#v; %v", n.Op, n)
    93  		return
    94  	}
    95  
    96  	switch n.Class {
    97  	case PAUTO, PPARAM, PPARAMOUT:
    98  		if !n.Used {
    99  			Prog(obj.ANOP)
   100  			return
   101  		}
   102  
   103  		if as == obj.AVARLIVE {
   104  			Gins(as, n, nil)
   105  		} else {
   106  			Gins(as, nil, n)
   107  		}
   108  	}
   109  }
   110  
   111  func Gvardef(n *Node) {
   112  	gvardefx(n, obj.AVARDEF)
   113  }
   114  
   115  func Gvarkill(n *Node) {
   116  	gvardefx(n, obj.AVARKILL)
   117  }
   118  
   119  func Gvarlive(n *Node) {
   120  	gvardefx(n, obj.AVARLIVE)
   121  }
   122  
   123  func removevardef(firstp *obj.Prog) {
   124  	for p := firstp; p != nil; p = p.Link {
   125  		for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL || p.Link.As == obj.AVARLIVE) {
   126  			p.Link = p.Link.Link
   127  		}
   128  		if p.To.Type == obj.TYPE_BRANCH {
   129  			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) {
   130  				p.To.Val = p.To.Val.(*obj.Prog).Link
   131  			}
   132  		}
   133  	}
   134  }
   135  
   136  func emitptrargsmap() {
   137  	if Curfn.Func.Nname.Sym.Name == "_" {
   138  		return
   139  	}
   140  	sym := lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
   141  
   142  	nptr := int(Curfn.Type.ArgWidth() / int64(Widthptr))
   143  	bv := bvalloc(int32(nptr) * 2)
   144  	nbitmap := 1
   145  	if Curfn.Type.Results().NumFields() > 0 {
   146  		nbitmap = 2
   147  	}
   148  	off := duint32(sym, 0, uint32(nbitmap))
   149  	off = duint32(sym, off, uint32(bv.n))
   150  	var xoffset int64
   151  	if Curfn.IsMethod() {
   152  		xoffset = 0
   153  		onebitwalktype1(Curfn.Type.Recvs(), &xoffset, bv)
   154  	}
   155  
   156  	if Curfn.Type.Params().NumFields() > 0 {
   157  		xoffset = 0
   158  		onebitwalktype1(Curfn.Type.Params(), &xoffset, bv)
   159  	}
   160  
   161  	off = dbvec(sym, off, bv)
   162  	if Curfn.Type.Results().NumFields() > 0 {
   163  		xoffset = 0
   164  		onebitwalktype1(Curfn.Type.Results(), &xoffset, bv)
   165  		off = dbvec(sym, off, bv)
   166  	}
   167  
   168  	ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
   169  }
   170  
   171  // cmpstackvarlt reports whether the stack variable a sorts before b.
   172  //
   173  // Sort the list of stack variables. Autos after anything else,
   174  // within autos, unused after used, within used, things with
   175  // pointers first, zeroed things first, and then decreasing size.
   176  // Because autos are laid out in decreasing addresses
   177  // on the stack, pointers first, zeroed things first and decreasing size
   178  // really means, in memory, things with pointers needing zeroing at
   179  // the top of the stack and increasing in size.
   180  // Non-autos sort on offset.
   181  func cmpstackvarlt(a, b *Node) bool {
   182  	if (a.Class == PAUTO) != (b.Class == PAUTO) {
   183  		return b.Class == PAUTO
   184  	}
   185  
   186  	if a.Class != PAUTO {
   187  		return a.Xoffset < b.Xoffset
   188  	}
   189  
   190  	if a.Used != b.Used {
   191  		return a.Used
   192  	}
   193  
   194  	ap := haspointers(a.Type)
   195  	bp := haspointers(b.Type)
   196  	if ap != bp {
   197  		return ap
   198  	}
   199  
   200  	ap = a.Name.Needzero
   201  	bp = b.Name.Needzero
   202  	if ap != bp {
   203  		return ap
   204  	}
   205  
   206  	if a.Type.Width != b.Type.Width {
   207  		return a.Type.Width > b.Type.Width
   208  	}
   209  
   210  	return a.Sym.Name < b.Sym.Name
   211  }
   212  
   213  // byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
   214  type byStackVar []*Node
   215  
   216  func (s byStackVar) Len() int           { return len(s) }
   217  func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
   218  func (s byStackVar) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   219  
   220  var scratchFpMem *Node
   221  
   222  func (s *ssaExport) AllocFrame(f *ssa.Func) {
   223  	Stksize = 0
   224  	stkptrsize = 0
   225  
   226  	// Mark the PAUTO's unused.
   227  	for _, ln := range Curfn.Func.Dcl {
   228  		if ln.Class == PAUTO {
   229  			ln.Used = false
   230  		}
   231  	}
   232  
   233  	for _, l := range f.RegAlloc {
   234  		if ls, ok := l.(ssa.LocalSlot); ok {
   235  			ls.N.(*Node).Used = true
   236  		}
   237  
   238  	}
   239  
   240  	scratchUsed := false
   241  	for _, b := range f.Blocks {
   242  		for _, v := range b.Values {
   243  			switch a := v.Aux.(type) {
   244  			case *ssa.ArgSymbol:
   245  				a.Node.(*Node).Used = true
   246  			case *ssa.AutoSymbol:
   247  				a.Node.(*Node).Used = true
   248  			}
   249  
   250  			if !scratchUsed {
   251  				scratchUsed = v.Op.UsesScratch()
   252  			}
   253  		}
   254  	}
   255  
   256  	if f.Config.NeedsFpScratch {
   257  		scratchFpMem = temp(Types[TUINT64])
   258  		scratchFpMem.Used = scratchUsed
   259  	}
   260  
   261  	sort.Sort(byStackVar(Curfn.Func.Dcl))
   262  
   263  	// Reassign stack offsets of the locals that are used.
   264  	for i, n := range Curfn.Func.Dcl {
   265  		if n.Op != ONAME || n.Class != PAUTO {
   266  			continue
   267  		}
   268  		if !n.Used {
   269  			Curfn.Func.Dcl = Curfn.Func.Dcl[:i]
   270  			break
   271  		}
   272  
   273  		dowidth(n.Type)
   274  		w := n.Type.Width
   275  		if w >= Thearch.MAXWIDTH || w < 0 {
   276  			Fatalf("bad width")
   277  		}
   278  		Stksize += w
   279  		Stksize = Rnd(Stksize, int64(n.Type.Align))
   280  		if haspointers(n.Type) {
   281  			stkptrsize = Stksize
   282  		}
   283  		if Thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
   284  			Stksize = Rnd(Stksize, int64(Widthptr))
   285  		}
   286  		if Stksize >= 1<<31 {
   287  			setlineno(Curfn)
   288  			yyerror("stack frame too large (>2GB)")
   289  		}
   290  
   291  		n.Xoffset = -Stksize
   292  	}
   293  
   294  	Stksize = Rnd(Stksize, int64(Widthreg))
   295  	stkptrsize = Rnd(stkptrsize, int64(Widthreg))
   296  }
   297  
   298  func compile(fn *Node) {
   299  	if Newproc == nil {
   300  		Newproc = Sysfunc("newproc")
   301  		Deferproc = Sysfunc("deferproc")
   302  		Deferreturn = Sysfunc("deferreturn")
   303  		Duffcopy = Sysfunc("duffcopy")
   304  		Duffzero = Sysfunc("duffzero")
   305  		panicindex = Sysfunc("panicindex")
   306  		panicslice = Sysfunc("panicslice")
   307  		panicdivide = Sysfunc("panicdivide")
   308  		growslice = Sysfunc("growslice")
   309  		panicdottypeE = Sysfunc("panicdottypeE")
   310  		panicdottypeI = Sysfunc("panicdottypeI")
   311  		panicnildottype = Sysfunc("panicnildottype")
   312  		assertE2I = Sysfunc("assertE2I")
   313  		assertE2I2 = Sysfunc("assertE2I2")
   314  		assertI2I = Sysfunc("assertI2I")
   315  		assertI2I2 = Sysfunc("assertI2I2")
   316  	}
   317  
   318  	defer func(lno src.XPos) {
   319  		lineno = lno
   320  	}(setlineno(fn))
   321  
   322  	Curfn = fn
   323  	dowidth(Curfn.Type)
   324  
   325  	if fn.Nbody.Len() == 0 {
   326  		if pure_go || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
   327  			yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
   328  			return
   329  		}
   330  
   331  		emitptrargsmap()
   332  		return
   333  	}
   334  
   335  	saveerrors()
   336  
   337  	if Curfn.Type.FuncType().Outnamed {
   338  		// add clearing of the output parameters
   339  		for _, t := range Curfn.Type.Results().Fields().Slice() {
   340  			if t.Nname != nil {
   341  				n := nod(OAS, t.Nname, nil)
   342  				n = typecheck(n, Etop)
   343  				Curfn.Nbody.Prepend(n)
   344  			}
   345  		}
   346  	}
   347  
   348  	order(Curfn)
   349  	if nerrors != 0 {
   350  		return
   351  	}
   352  
   353  	hasdefer = false
   354  	walk(Curfn)
   355  	if nerrors != 0 {
   356  		return
   357  	}
   358  	if instrumenting {
   359  		instrument(Curfn)
   360  	}
   361  	if nerrors != 0 {
   362  		return
   363  	}
   364  
   365  	// Build an SSA backend function.
   366  	ssafn := buildssa(Curfn)
   367  	if nerrors != 0 {
   368  		return
   369  	}
   370  
   371  	newplist()
   372  
   373  	setlineno(Curfn)
   374  
   375  	nam := Curfn.Func.Nname
   376  	if isblank(nam) {
   377  		nam = nil
   378  	}
   379  	ptxt := Gins(obj.ATEXT, nam, nil)
   380  	ptxt.From3 = new(obj.Addr)
   381  	if fn.Func.Dupok {
   382  		ptxt.From3.Offset |= obj.DUPOK
   383  	}
   384  	if fn.Func.Wrapper {
   385  		ptxt.From3.Offset |= obj.WRAPPER
   386  	}
   387  	if fn.Func.NoFramePointer {
   388  		ptxt.From3.Offset |= obj.NOFRAME
   389  	}
   390  	if fn.Func.Needctxt {
   391  		ptxt.From3.Offset |= obj.NEEDCTXT
   392  	}
   393  	if fn.Func.Pragma&Nosplit != 0 {
   394  		ptxt.From3.Offset |= obj.NOSPLIT
   395  	}
   396  	if fn.Func.ReflectMethod {
   397  		ptxt.From3.Offset |= obj.REFLECTMETHOD
   398  	}
   399  	if fn.Func.Pragma&Systemstack != 0 {
   400  		ptxt.From.Sym.Set(obj.AttrCFunc, true)
   401  		if fn.Func.Pragma&Nosplit != 0 {
   402  			yyerror("go:nosplit and go:systemstack cannot be combined")
   403  		}
   404  	}
   405  
   406  	// Clumsy but important.
   407  	// See test/recover.go for test cases and src/reflect/value.go
   408  	// for the actual functions being considered.
   409  	if myimportpath == "reflect" {
   410  		if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
   411  			ptxt.From3.Offset |= obj.WRAPPER
   412  		}
   413  	}
   414  
   415  	gcargs := makefuncdatasym("gcargs·", obj.FUNCDATA_ArgsPointerMaps)
   416  	gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps)
   417  
   418  	if obj.Fieldtrack_enabled != 0 && len(Curfn.Func.FieldTrack) > 0 {
   419  		trackSyms := make([]*Sym, 0, len(Curfn.Func.FieldTrack))
   420  		for sym := range Curfn.Func.FieldTrack {
   421  			trackSyms = append(trackSyms, sym)
   422  		}
   423  		sort.Sort(symByName(trackSyms))
   424  		for _, sym := range trackSyms {
   425  			gtrack(sym)
   426  		}
   427  	}
   428  
   429  	gendebug(ptxt.From.Sym, fn.Func.Dcl)
   430  
   431  	genssa(ssafn, ptxt, gcargs, gclocals)
   432  	ssafn.Free()
   433  }
   434  
   435  func gendebug(fn *obj.LSym, decls []*Node) {
   436  	if fn == nil {
   437  		return
   438  	}
   439  
   440  	for _, n := range decls {
   441  		if n.Op != ONAME { // might be OTYPE or OLITERAL
   442  			continue
   443  		}
   444  
   445  		var name obj.AddrName
   446  		switch n.Class {
   447  		case PAUTO:
   448  			if !n.Used {
   449  				continue
   450  			}
   451  			name = obj.NAME_AUTO
   452  		case PPARAM, PPARAMOUT:
   453  			name = obj.NAME_PARAM
   454  		default:
   455  			continue
   456  		}
   457  
   458  		a := &obj.Auto{
   459  			Asym:    obj.Linklookup(Ctxt, n.Sym.Name, 0),
   460  			Aoffset: int32(n.Xoffset),
   461  			Name:    name,
   462  			Gotype:  Linksym(ngotype(n)),
   463  		}
   464  
   465  		a.Link = fn.Autom
   466  		fn.Autom = a
   467  	}
   468  }
   469  
   470  type symByName []*Sym
   471  
   472  func (a symByName) Len() int           { return len(a) }
   473  func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
   474  func (a symByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }