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