github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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/compile/internal/types"
    10  	"cmd/internal/dwarf"
    11  	"cmd/internal/obj"
    12  	"cmd/internal/src"
    13  	"cmd/internal/sys"
    14  	"fmt"
    15  	"sort"
    16  )
    17  
    18  // "Portable" code generation.
    19  
    20  func makefuncdatasym(pp *Progs, nameprefix string, funcdatakind int64, curfn *Node) *types.Sym {
    21  	// This symbol requires a unique, reproducible name;
    22  	// unique to avoid duplicate symbols,
    23  	// and reproducible for reproducible builds and toolstash.
    24  	// The function name will usually suffice.
    25  	suffix := curfn.Func.Nname.Sym.Name
    26  	if suffix == "_" {
    27  		// It is possible to have multiple functions called _,
    28  		// so in this rare case, use instead the function's position.
    29  		// This formatted string will be meaningless gibberish, but that's ok.
    30  		// It will be unique and reproducible, and it is rare anyway.
    31  		// Note that we can't just always use the position;
    32  		// it is possible to have multiple autogenerated functions at the same position.
    33  		// Fortunately, no autogenerated functions are called _.
    34  		if curfn.Pos == autogeneratedPos {
    35  			Fatalf("autogenerated func _")
    36  		}
    37  		suffix = fmt.Sprintf("%v", curfn.Pos)
    38  	}
    39  	// Add in the package path as well.
    40  	// When generating wrappers, we can end up compiling a function belonging
    41  	// to other packages, which might have a name that collides with one in our package.
    42  	symname := nameprefix + curfn.Func.Nname.Sym.Pkg.Path + "." + suffix
    43  
    44  	sym := lookup(symname)
    45  	p := pp.Prog(obj.AFUNCDATA)
    46  	Addrconst(&p.From, funcdatakind)
    47  	p.To.Type = obj.TYPE_MEM
    48  	p.To.Name = obj.NAME_EXTERN
    49  	p.To.Sym = Linksym(sym)
    50  	return sym
    51  }
    52  
    53  // TODO(mdempsky): Update to reference OpVar{Def,Kill,Live} instead
    54  // and move to plive.go.
    55  
    56  // VARDEF is an annotation for the liveness analysis, marking a place
    57  // where a complete initialization (definition) of a variable begins.
    58  // Since the liveness analysis can see initialization of single-word
    59  // variables quite easy, gvardef is usually only called for multi-word
    60  // or 'fat' variables, those satisfying isfat(n->type).
    61  // However, gvardef is also called when a non-fat variable is initialized
    62  // via a block move; the only time this happens is when you have
    63  //	return f()
    64  // for a function with multiple return values exactly matching the return
    65  // types of the current function.
    66  //
    67  // A 'VARDEF x' annotation in the instruction stream tells the liveness
    68  // analysis to behave as though the variable x is being initialized at that
    69  // point in the instruction stream. The VARDEF must appear before the
    70  // actual (multi-instruction) initialization, and it must also appear after
    71  // any uses of the previous value, if any. For example, if compiling:
    72  //
    73  //	x = x[1:]
    74  //
    75  // it is important to generate code like:
    76  //
    77  //	base, len, cap = pieces of x[1:]
    78  //	VARDEF x
    79  //	x = {base, len, cap}
    80  //
    81  // If instead the generated code looked like:
    82  //
    83  //	VARDEF x
    84  //	base, len, cap = pieces of x[1:]
    85  //	x = {base, len, cap}
    86  //
    87  // then the liveness analysis would decide the previous value of x was
    88  // unnecessary even though it is about to be used by the x[1:] computation.
    89  // Similarly, if the generated code looked like:
    90  //
    91  //	base, len, cap = pieces of x[1:]
    92  //	x = {base, len, cap}
    93  //	VARDEF x
    94  //
    95  // then the liveness analysis will not preserve the new value of x, because
    96  // the VARDEF appears to have "overwritten" it.
    97  //
    98  // VARDEF is a bit of a kludge to work around the fact that the instruction
    99  // stream is working on single-word values but the liveness analysis
   100  // wants to work on individual variables, which might be multi-word
   101  // aggregates. It might make sense at some point to look into letting
   102  // the liveness analysis work on single-word values as well, although
   103  // there are complications around interface values, slices, and strings,
   104  // all of which cannot be treated as individual words.
   105  //
   106  // VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
   107  // even if its address has been taken. That is, a VARKILL annotation asserts
   108  // that its argument is certainly dead, for use when the liveness analysis
   109  // would not otherwise be able to deduce that fact.
   110  
   111  func emitptrargsmap() {
   112  	if Curfn.Func.Nname.Sym.Name == "_" {
   113  		return
   114  	}
   115  	sym := lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
   116  
   117  	nptr := int(Curfn.Type.ArgWidth() / int64(Widthptr))
   118  	bv := bvalloc(int32(nptr) * 2)
   119  	nbitmap := 1
   120  	if Curfn.Type.Results().NumFields() > 0 {
   121  		nbitmap = 2
   122  	}
   123  	off := duint32(sym, 0, uint32(nbitmap))
   124  	off = duint32(sym, off, uint32(bv.n))
   125  	var xoffset int64
   126  	if Curfn.IsMethod() {
   127  		xoffset = 0
   128  		onebitwalktype1(Curfn.Type.Recvs(), &xoffset, bv)
   129  	}
   130  
   131  	if Curfn.Type.Params().NumFields() > 0 {
   132  		xoffset = 0
   133  		onebitwalktype1(Curfn.Type.Params(), &xoffset, bv)
   134  	}
   135  
   136  	off = dbvec(sym, off, bv)
   137  	if Curfn.Type.Results().NumFields() > 0 {
   138  		xoffset = 0
   139  		onebitwalktype1(Curfn.Type.Results(), &xoffset, bv)
   140  		off = dbvec(sym, off, bv)
   141  	}
   142  
   143  	ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
   144  }
   145  
   146  // cmpstackvarlt reports whether the stack variable a sorts before b.
   147  //
   148  // Sort the list of stack variables. Autos after anything else,
   149  // within autos, unused after used, within used, things with
   150  // pointers first, zeroed things first, and then decreasing size.
   151  // Because autos are laid out in decreasing addresses
   152  // on the stack, pointers first, zeroed things first and decreasing size
   153  // really means, in memory, things with pointers needing zeroing at
   154  // the top of the stack and increasing in size.
   155  // Non-autos sort on offset.
   156  func cmpstackvarlt(a, b *Node) bool {
   157  	if (a.Class == PAUTO) != (b.Class == PAUTO) {
   158  		return b.Class == PAUTO
   159  	}
   160  
   161  	if a.Class != PAUTO {
   162  		return a.Xoffset < b.Xoffset
   163  	}
   164  
   165  	if a.Used() != b.Used() {
   166  		return a.Used()
   167  	}
   168  
   169  	ap := types.Haspointers(a.Type)
   170  	bp := types.Haspointers(b.Type)
   171  	if ap != bp {
   172  		return ap
   173  	}
   174  
   175  	ap = a.Name.Needzero()
   176  	bp = b.Name.Needzero()
   177  	if ap != bp {
   178  		return ap
   179  	}
   180  
   181  	if a.Type.Width != b.Type.Width {
   182  		return a.Type.Width > b.Type.Width
   183  	}
   184  
   185  	return a.Sym.Name < b.Sym.Name
   186  }
   187  
   188  // byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
   189  type byStackVar []*Node
   190  
   191  func (s byStackVar) Len() int           { return len(s) }
   192  func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
   193  func (s byStackVar) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   194  
   195  func (s *ssafn) AllocFrame(f *ssa.Func) {
   196  	s.stksize = 0
   197  	s.stkptrsize = 0
   198  	fn := s.curfn.Func
   199  
   200  	// Mark the PAUTO's unused.
   201  	for _, ln := range fn.Dcl {
   202  		if ln.Class == PAUTO {
   203  			ln.SetUsed(false)
   204  		}
   205  	}
   206  
   207  	for _, l := range f.RegAlloc {
   208  		if ls, ok := l.(ssa.LocalSlot); ok {
   209  			ls.N.(*Node).SetUsed(true)
   210  		}
   211  	}
   212  
   213  	scratchUsed := false
   214  	for _, b := range f.Blocks {
   215  		for _, v := range b.Values {
   216  			switch a := v.Aux.(type) {
   217  			case *ssa.ArgSymbol:
   218  				n := a.Node.(*Node)
   219  				// Don't modify nodfp; it is a global.
   220  				if n != nodfp {
   221  					n.SetUsed(true)
   222  				}
   223  			case *ssa.AutoSymbol:
   224  				a.Node.(*Node).SetUsed(true)
   225  			}
   226  
   227  			if !scratchUsed {
   228  				scratchUsed = v.Op.UsesScratch()
   229  			}
   230  		}
   231  	}
   232  
   233  	if f.Config.NeedsFpScratch && scratchUsed {
   234  		s.scratchFpMem = tempAt(src.NoXPos, s.curfn, types.Types[TUINT64])
   235  	}
   236  
   237  	sort.Sort(byStackVar(fn.Dcl))
   238  
   239  	// Reassign stack offsets of the locals that are used.
   240  	for i, n := range fn.Dcl {
   241  		if n.Op != ONAME || n.Class != PAUTO {
   242  			continue
   243  		}
   244  		if !n.Used() {
   245  			fn.Dcl = fn.Dcl[:i]
   246  			break
   247  		}
   248  
   249  		dowidth(n.Type)
   250  		w := n.Type.Width
   251  		if w >= thearch.MAXWIDTH || w < 0 {
   252  			Fatalf("bad width")
   253  		}
   254  		s.stksize += w
   255  		s.stksize = Rnd(s.stksize, int64(n.Type.Align))
   256  		if types.Haspointers(n.Type) {
   257  			s.stkptrsize = s.stksize
   258  		}
   259  		if thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
   260  			s.stksize = Rnd(s.stksize, int64(Widthptr))
   261  		}
   262  		n.Xoffset = -s.stksize
   263  	}
   264  
   265  	s.stksize = Rnd(s.stksize, int64(Widthreg))
   266  	s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg))
   267  }
   268  
   269  func compile(fn *Node) {
   270  	Curfn = fn
   271  	dowidth(fn.Type)
   272  
   273  	if fn.Nbody.Len() == 0 {
   274  		emitptrargsmap()
   275  		return
   276  	}
   277  
   278  	saveerrors()
   279  
   280  	order(fn)
   281  	if nerrors != 0 {
   282  		return
   283  	}
   284  
   285  	walk(fn)
   286  	if nerrors != 0 {
   287  		return
   288  	}
   289  	checkcontrolflow(fn)
   290  	if nerrors != 0 {
   291  		return
   292  	}
   293  	if instrumenting {
   294  		instrument(fn)
   295  	}
   296  
   297  	// From this point, there should be no uses of Curfn. Enforce that.
   298  	Curfn = nil
   299  
   300  	// Set up the function's LSym early to avoid data races with the assemblers.
   301  	fn.Func.initLSym()
   302  
   303  	// Build an SSA backend function.
   304  	ssafn := buildssa(fn)
   305  	pp := newProgs(fn)
   306  	genssa(ssafn, pp)
   307  	fieldtrack(pp.Text.From.Sym, fn.Func.FieldTrack)
   308  	if pp.Text.To.Offset < 1<<31 {
   309  		pp.Flush()
   310  	} else {
   311  		largeStackFrames = append(largeStackFrames, fn.Pos)
   312  	}
   313  	pp.Free()
   314  }
   315  
   316  func debuginfo(fnsym *obj.LSym, curfn interface{}) []*dwarf.Var {
   317  	fn := curfn.(*Node)
   318  	if expect := Linksym(fn.Func.Nname.Sym); fnsym != expect {
   319  		Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
   320  	}
   321  
   322  	var vars []*dwarf.Var
   323  	for _, n := range fn.Func.Dcl {
   324  		if n.Op != ONAME { // might be OTYPE or OLITERAL
   325  			continue
   326  		}
   327  
   328  		var name obj.AddrName
   329  		var abbrev int
   330  		offs := n.Xoffset
   331  
   332  		switch n.Class {
   333  		case PAUTO:
   334  			if !n.Used() {
   335  				Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
   336  			}
   337  			name = obj.NAME_AUTO
   338  
   339  			abbrev = dwarf.DW_ABRV_AUTO
   340  			if Ctxt.FixedFrameSize() == 0 {
   341  				offs -= int64(Widthptr)
   342  			}
   343  			if obj.Framepointer_enabled(obj.GOOS, obj.GOARCH) {
   344  				offs -= int64(Widthptr)
   345  			}
   346  
   347  		case PPARAM, PPARAMOUT:
   348  			name = obj.NAME_PARAM
   349  
   350  			abbrev = dwarf.DW_ABRV_PARAM
   351  			offs += Ctxt.FixedFrameSize()
   352  
   353  		default:
   354  			continue
   355  		}
   356  
   357  		gotype := Linksym(ngotype(n))
   358  		fnsym.Autom = append(fnsym.Autom, &obj.Auto{
   359  			Asym:    Ctxt.Lookup(n.Sym.Name, 0),
   360  			Aoffset: int32(n.Xoffset),
   361  			Name:    name,
   362  			Gotype:  gotype,
   363  		})
   364  
   365  		if n.IsAutoTmp() {
   366  			continue
   367  		}
   368  
   369  		typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
   370  		vars = append(vars, &dwarf.Var{
   371  			Name:   n.Sym.Name,
   372  			Abbrev: abbrev,
   373  			Offset: int32(offs),
   374  			Type:   Ctxt.Lookup(typename, 0),
   375  		})
   376  	}
   377  
   378  	// Stable sort so that ties are broken with declaration order.
   379  	sort.Stable(dwarf.VarsByOffset(vars))
   380  
   381  	return vars
   382  }
   383  
   384  // fieldtrack adds R_USEFIELD relocations to fnsym to record any
   385  // struct fields that it used.
   386  func fieldtrack(fnsym *obj.LSym, tracked map[*types.Sym]struct{}) {
   387  	if fnsym == nil {
   388  		return
   389  	}
   390  	if obj.Fieldtrack_enabled == 0 || len(tracked) == 0 {
   391  		return
   392  	}
   393  
   394  	trackSyms := make([]*types.Sym, 0, len(tracked))
   395  	for sym := range tracked {
   396  		trackSyms = append(trackSyms, sym)
   397  	}
   398  	sort.Sort(symByName(trackSyms))
   399  	for _, sym := range trackSyms {
   400  		r := obj.Addrel(fnsym)
   401  		r.Sym = Linksym(sym)
   402  		r.Type = obj.R_USEFIELD
   403  	}
   404  }
   405  
   406  type symByName []*types.Sym
   407  
   408  func (a symByName) Len() int           { return len(a) }
   409  func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
   410  func (a symByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }