2015-02-13 14:40:36 -05:00
|
|
|
// Copyright 2011 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
|
|
|
|
|
import (
|
2016-10-03 12:26:25 -07:00
|
|
|
"cmd/compile/internal/ssa"
|
2017-03-06 07:32:37 -08:00
|
|
|
"cmd/internal/dwarf"
|
2015-02-13 14:40:36 -05:00
|
|
|
"cmd/internal/obj"
|
2017-03-22 20:27:54 -07:00
|
|
|
"cmd/internal/src"
|
2016-04-06 12:01:40 -07:00
|
|
|
"cmd/internal/sys"
|
2015-02-13 14:40:36 -05:00
|
|
|
"fmt"
|
2016-02-25 10:35:19 -08:00
|
|
|
"sort"
|
2015-02-13 14:40:36 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// "Portable" code generation.
|
|
|
|
|
|
2017-03-30 16:23:01 -07:00
|
|
|
func makefuncdatasym(pp *Progs, nameprefix string, funcdatakind int64, curfn *Node) *Sym {
|
|
|
|
|
// This symbol requires a unique, reproducible name;
|
|
|
|
|
// unique to avoid duplicate symbols,
|
|
|
|
|
// and reproducible for reproducible builds and toolstash.
|
|
|
|
|
// The function name will usually suffice.
|
|
|
|
|
suffix := curfn.Func.Nname.Sym.Name
|
|
|
|
|
if suffix == "_" {
|
|
|
|
|
// It is possible to have multiple functions called _,
|
|
|
|
|
// so in this rare case, use instead the function's position.
|
|
|
|
|
// This formatted string will be meaningless gibberish, but that's ok.
|
|
|
|
|
// It will be unique and reproducible, and it is rare anyway.
|
|
|
|
|
// Note that we can't just always use the position;
|
|
|
|
|
// it is possible to have multiple autogenerated functions at the same position.
|
|
|
|
|
// Fortunately, no autogenerated functions are called _.
|
|
|
|
|
if curfn.Pos == autogeneratedPos {
|
|
|
|
|
Fatalf("autogenerated func _")
|
|
|
|
|
}
|
|
|
|
|
suffix = fmt.Sprintf("%v", curfn.Pos)
|
|
|
|
|
}
|
|
|
|
|
// Add in the package path as well.
|
|
|
|
|
// When generating wrappers, we can end up compiling a function belonging
|
|
|
|
|
// to other packages, which might have a name that collides with one in our package.
|
|
|
|
|
symname := nameprefix + curfn.Func.Nname.Sym.Pkg.Path + "." + suffix
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2017-03-30 16:23:01 -07:00
|
|
|
sym := lookup(symname)
|
2017-03-22 16:43:42 -07:00
|
|
|
p := pp.Prog(obj.AFUNCDATA)
|
2016-09-29 16:22:43 -07:00
|
|
|
Addrconst(&p.From, funcdatakind)
|
2017-03-09 18:32:17 -08:00
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Name = obj.NAME_EXTERN
|
|
|
|
|
p.To.Sym = Linksym(sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
return sym
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-09 18:32:17 -08:00
|
|
|
// TODO(mdempsky): Update to reference OpVar{Def,Kill,Live} instead
|
|
|
|
|
// and move to plive.go.
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
// VARDEF is an annotation for the liveness analysis, marking a place
|
|
|
|
|
// where a complete initialization (definition) of a variable begins.
|
|
|
|
|
// Since the liveness analysis can see initialization of single-word
|
|
|
|
|
// variables quite easy, gvardef is usually only called for multi-word
|
|
|
|
|
// or 'fat' variables, those satisfying isfat(n->type).
|
|
|
|
|
// However, gvardef is also called when a non-fat variable is initialized
|
|
|
|
|
// via a block move; the only time this happens is when you have
|
|
|
|
|
// return f()
|
|
|
|
|
// for a function with multiple return values exactly matching the return
|
|
|
|
|
// types of the current function.
|
|
|
|
|
//
|
|
|
|
|
// A 'VARDEF x' annotation in the instruction stream tells the liveness
|
|
|
|
|
// analysis to behave as though the variable x is being initialized at that
|
|
|
|
|
// point in the instruction stream. The VARDEF must appear before the
|
|
|
|
|
// actual (multi-instruction) initialization, and it must also appear after
|
|
|
|
|
// any uses of the previous value, if any. For example, if compiling:
|
|
|
|
|
//
|
|
|
|
|
// x = x[1:]
|
|
|
|
|
//
|
|
|
|
|
// it is important to generate code like:
|
|
|
|
|
//
|
|
|
|
|
// base, len, cap = pieces of x[1:]
|
|
|
|
|
// VARDEF x
|
|
|
|
|
// x = {base, len, cap}
|
|
|
|
|
//
|
|
|
|
|
// If instead the generated code looked like:
|
|
|
|
|
//
|
|
|
|
|
// VARDEF x
|
|
|
|
|
// base, len, cap = pieces of x[1:]
|
|
|
|
|
// x = {base, len, cap}
|
|
|
|
|
//
|
|
|
|
|
// then the liveness analysis would decide the previous value of x was
|
|
|
|
|
// unnecessary even though it is about to be used by the x[1:] computation.
|
|
|
|
|
// Similarly, if the generated code looked like:
|
|
|
|
|
//
|
|
|
|
|
// base, len, cap = pieces of x[1:]
|
|
|
|
|
// x = {base, len, cap}
|
|
|
|
|
// VARDEF x
|
|
|
|
|
//
|
|
|
|
|
// then the liveness analysis will not preserve the new value of x, because
|
|
|
|
|
// the VARDEF appears to have "overwritten" it.
|
|
|
|
|
//
|
|
|
|
|
// VARDEF is a bit of a kludge to work around the fact that the instruction
|
|
|
|
|
// stream is working on single-word values but the liveness analysis
|
|
|
|
|
// wants to work on individual variables, which might be multi-word
|
|
|
|
|
// aggregates. It might make sense at some point to look into letting
|
|
|
|
|
// the liveness analysis work on single-word values as well, although
|
|
|
|
|
// there are complications around interface values, slices, and strings,
|
|
|
|
|
// all of which cannot be treated as individual words.
|
|
|
|
|
//
|
|
|
|
|
// VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
|
|
|
|
|
// even if its address has been taken. That is, a VARKILL annotation asserts
|
|
|
|
|
// that its argument is certainly dead, for use when the liveness analysis
|
|
|
|
|
// would not otherwise be able to deduce that fact.
|
|
|
|
|
|
|
|
|
|
func emitptrargsmap() {
|
2015-11-04 15:54:41 -05:00
|
|
|
if Curfn.Func.Nname.Sym.Name == "_" {
|
|
|
|
|
return
|
|
|
|
|
}
|
2016-09-15 15:45:10 +10:00
|
|
|
sym := lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-28 14:31:57 -07:00
|
|
|
nptr := int(Curfn.Type.ArgWidth() / int64(Widthptr))
|
2015-02-23 16:07:24 -05:00
|
|
|
bv := bvalloc(int32(nptr) * 2)
|
|
|
|
|
nbitmap := 1
|
2016-03-17 01:47:16 -07:00
|
|
|
if Curfn.Type.Results().NumFields() > 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
nbitmap = 2
|
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
off := duint32(sym, 0, uint32(nbitmap))
|
2015-02-13 14:40:36 -05:00
|
|
|
off = duint32(sym, off, uint32(bv.n))
|
2015-02-23 16:07:24 -05:00
|
|
|
var xoffset int64
|
2016-09-11 14:43:37 -07:00
|
|
|
if Curfn.IsMethod() {
|
2015-02-13 14:40:36 -05:00
|
|
|
xoffset = 0
|
2016-03-09 20:54:59 -08:00
|
|
|
onebitwalktype1(Curfn.Type.Recvs(), &xoffset, bv)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-17 01:47:16 -07:00
|
|
|
if Curfn.Type.Params().NumFields() > 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
xoffset = 0
|
2016-03-08 16:31:28 -08:00
|
|
|
onebitwalktype1(Curfn.Type.Params(), &xoffset, bv)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-10-11 10:23:14 -07:00
|
|
|
off = dbvec(sym, off, bv)
|
2016-03-17 01:47:16 -07:00
|
|
|
if Curfn.Type.Results().NumFields() > 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
xoffset = 0
|
2016-03-08 16:31:28 -08:00
|
|
|
onebitwalktype1(Curfn.Type.Results(), &xoffset, bv)
|
2016-10-11 10:23:14 -07:00
|
|
|
off = dbvec(sym, off, bv)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-04-18 08:14:08 +12:00
|
|
|
ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-09-15 21:43:53 +02:00
|
|
|
// cmpstackvarlt reports whether the stack variable a sorts before b.
|
2015-09-19 23:55:27 +02:00
|
|
|
//
|
2015-02-13 14:40:36 -05:00
|
|
|
// Sort the list of stack variables. Autos after anything else,
|
|
|
|
|
// within autos, unused after used, within used, things with
|
|
|
|
|
// pointers first, zeroed things first, and then decreasing size.
|
|
|
|
|
// Because autos are laid out in decreasing addresses
|
|
|
|
|
// on the stack, pointers first, zeroed things first and decreasing size
|
|
|
|
|
// really means, in memory, things with pointers needing zeroing at
|
|
|
|
|
// the top of the stack and increasing in size.
|
|
|
|
|
// Non-autos sort on offset.
|
2015-09-19 23:55:27 +02:00
|
|
|
func cmpstackvarlt(a, b *Node) bool {
|
2016-02-20 21:36:12 -08:00
|
|
|
if (a.Class == PAUTO) != (b.Class == PAUTO) {
|
|
|
|
|
return b.Class == PAUTO
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if a.Class != PAUTO {
|
2016-02-20 21:36:12 -08:00
|
|
|
return a.Xoffset < b.Xoffset
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-02-27 19:56:38 +02:00
|
|
|
if a.Used() != b.Used() {
|
|
|
|
|
return a.Used()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-09-19 23:55:27 +02:00
|
|
|
ap := haspointers(a.Type)
|
|
|
|
|
bp := haspointers(b.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
if ap != bp {
|
2015-09-19 23:55:27 +02:00
|
|
|
return ap
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-02-27 19:56:38 +02:00
|
|
|
ap = a.Name.Needzero()
|
|
|
|
|
bp = b.Name.Needzero()
|
2015-02-13 14:40:36 -05:00
|
|
|
if ap != bp {
|
2015-09-19 23:55:27 +02:00
|
|
|
return ap
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-20 21:36:12 -08:00
|
|
|
if a.Type.Width != b.Type.Width {
|
|
|
|
|
return a.Type.Width > b.Type.Width
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-09-19 23:55:27 +02:00
|
|
|
return a.Sym.Name < b.Sym.Name
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 10:35:19 -08:00
|
|
|
// byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
|
|
|
|
|
type byStackVar []*Node
|
|
|
|
|
|
|
|
|
|
func (s byStackVar) Len() int { return len(s) }
|
|
|
|
|
func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
|
|
|
|
|
func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
|
|
|
|
2017-03-17 07:49:22 -07:00
|
|
|
func (s *ssafn) AllocFrame(f *ssa.Func) {
|
2017-03-17 09:10:57 -07:00
|
|
|
s.stksize = 0
|
2017-03-17 09:19:56 -07:00
|
|
|
s.stkptrsize = 0
|
2017-03-17 07:49:22 -07:00
|
|
|
fn := s.curfn.Func
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// Mark the PAUTO's unused.
|
2017-03-17 07:49:22 -07:00
|
|
|
for _, ln := range fn.Dcl {
|
2016-02-25 10:35:19 -08:00
|
|
|
if ln.Class == PAUTO {
|
2017-02-27 19:56:38 +02:00
|
|
|
ln.SetUsed(false)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-03 12:26:25 -07:00
|
|
|
for _, l := range f.RegAlloc {
|
|
|
|
|
if ls, ok := l.(ssa.LocalSlot); ok {
|
2017-02-27 19:56:38 +02:00
|
|
|
ls.N.(*Node).SetUsed(true)
|
2016-10-03 12:26:25 -07:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-10-03 12:26:25 -07:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-10-03 12:26:25 -07:00
|
|
|
scratchUsed := false
|
|
|
|
|
for _, b := range f.Blocks {
|
|
|
|
|
for _, v := range b.Values {
|
|
|
|
|
switch a := v.Aux.(type) {
|
|
|
|
|
case *ssa.ArgSymbol:
|
2017-02-27 19:56:38 +02:00
|
|
|
a.Node.(*Node).SetUsed(true)
|
2016-10-03 12:26:25 -07:00
|
|
|
case *ssa.AutoSymbol:
|
2017-02-27 19:56:38 +02:00
|
|
|
a.Node.(*Node).SetUsed(true)
|
2016-10-03 12:26:25 -07:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-10-04 13:00:21 -07:00
|
|
|
if !scratchUsed {
|
|
|
|
|
scratchUsed = v.Op.UsesScratch()
|
2016-10-03 12:26:25 -07:00
|
|
|
}
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-03-30 14:34:16 -07:00
|
|
|
if f.Config.NeedsFpScratch && scratchUsed {
|
|
|
|
|
s.scratchFpMem = tempAt(src.NoXPos, s.curfn, Types[TUINT64])
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-03-17 07:49:22 -07:00
|
|
|
sort.Sort(byStackVar(fn.Dcl))
|
2016-10-03 12:26:25 -07:00
|
|
|
|
|
|
|
|
// Reassign stack offsets of the locals that are used.
|
2017-03-17 07:49:22 -07:00
|
|
|
for i, n := range fn.Dcl {
|
2016-10-03 12:26:25 -07:00
|
|
|
if n.Op != ONAME || n.Class != PAUTO {
|
2015-02-13 14:40:36 -05:00
|
|
|
continue
|
|
|
|
|
}
|
2017-02-27 19:56:38 +02:00
|
|
|
if !n.Used() {
|
2017-03-17 07:49:22 -07:00
|
|
|
fn.Dcl = fn.Dcl[:i]
|
2016-10-03 12:26:25 -07:00
|
|
|
break
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
dowidth(n.Type)
|
2016-10-03 12:26:25 -07:00
|
|
|
w := n.Type.Width
|
2017-03-17 13:35:36 -07:00
|
|
|
if w >= thearch.MAXWIDTH || w < 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("bad width")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2017-03-17 09:10:57 -07:00
|
|
|
s.stksize += w
|
|
|
|
|
s.stksize = Rnd(s.stksize, int64(n.Type.Align))
|
2015-02-13 14:40:36 -05:00
|
|
|
if haspointers(n.Type) {
|
2017-03-17 09:19:56 -07:00
|
|
|
s.stkptrsize = s.stksize
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2017-03-17 13:35:36 -07:00
|
|
|
if thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
|
2017-03-17 09:10:57 -07:00
|
|
|
s.stksize = Rnd(s.stksize, int64(Widthptr))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2017-03-17 09:10:57 -07:00
|
|
|
n.Xoffset = -s.stksize
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-03-17 09:10:57 -07:00
|
|
|
s.stksize = Rnd(s.stksize, int64(Widthreg))
|
2017-03-17 09:19:56 -07:00
|
|
|
s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func compile(fn *Node) {
|
|
|
|
|
Curfn = fn
|
2017-03-14 09:12:55 -07:00
|
|
|
dowidth(fn.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-04-24 13:50:26 -07:00
|
|
|
if fn.Nbody.Len() == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
emitptrargsmap()
|
2016-03-07 22:05:49 -08:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
saveerrors()
|
|
|
|
|
|
2017-03-14 09:12:55 -07:00
|
|
|
order(fn)
|
2015-02-13 14:40:36 -05:00
|
|
|
if nerrors != 0 {
|
2016-03-07 22:05:49 -08:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-03-14 09:12:55 -07:00
|
|
|
walk(fn)
|
2015-02-13 14:40:36 -05:00
|
|
|
if nerrors != 0 {
|
2016-03-07 22:05:49 -08:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2017-03-14 11:05:03 -07:00
|
|
|
checkcontrolflow(fn)
|
|
|
|
|
if nerrors != 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
2015-10-20 10:00:07 -07:00
|
|
|
if instrumenting {
|
2017-03-14 09:12:55 -07:00
|
|
|
instrument(fn)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-03-23 16:39:11 -07:00
|
|
|
// From this point, there should be no uses of Curfn. Enforce that.
|
|
|
|
|
Curfn = nil
|
|
|
|
|
|
2015-06-12 11:01:13 -07:00
|
|
|
// Build an SSA backend function.
|
2017-03-14 09:12:55 -07:00
|
|
|
ssafn := buildssa(fn)
|
2017-03-22 16:43:42 -07:00
|
|
|
pp := newProgs(fn)
|
|
|
|
|
genssa(ssafn, pp)
|
|
|
|
|
fieldtrack(pp.Text.From.Sym, fn.Func.FieldTrack)
|
cmd/compile: rework reporting of oversized stack frames
We don't support stack frames over 2GB.
Rather than detect this during backend compilation,
check for it at the end of compilation.
This is arguably a more accurate check anyway,
since it takes into account the full frame,
including local stack, arguments, and arch-specific
rounding, although it's unlikely anyone would ever notice.
Also, rather than reporting the error right away,
take note of it and report it later, at the top level.
This is not relevant now, but it will help with making
the backend concurrent, as the append to the list of
oversized functions can be cheaply protected by a plain mutex.
Updates #15756
Updates #19250
Change-Id: Id3fa21906616d62e9dc66e27a17fd5f83304e96e
Reviewed-on: https://go-review.googlesource.com/38972
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2017-03-30 11:46:45 -07:00
|
|
|
if pp.Text.To.Offset >= 1<<31 {
|
|
|
|
|
largeStackFrames = append(largeStackFrames, fn.Pos)
|
|
|
|
|
return
|
|
|
|
|
}
|
2017-03-22 16:43:42 -07:00
|
|
|
pp.Flush()
|
2017-02-06 17:06:02 -08:00
|
|
|
}
|
|
|
|
|
|
2017-03-23 16:39:04 -07:00
|
|
|
func debuginfo(fnsym *obj.LSym, curfn interface{}) []*dwarf.Var {
|
|
|
|
|
fn := curfn.(*Node)
|
|
|
|
|
if expect := Linksym(fn.Func.Nname.Sym); fnsym != expect {
|
2017-03-06 07:32:37 -08:00
|
|
|
Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
|
2017-03-03 16:45:21 -08:00
|
|
|
}
|
|
|
|
|
|
2017-03-06 07:32:37 -08:00
|
|
|
var vars []*dwarf.Var
|
2017-03-23 16:39:04 -07:00
|
|
|
for _, n := range fn.Func.Dcl {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Op != ONAME { // might be OTYPE or OLITERAL
|
|
|
|
|
continue
|
|
|
|
|
}
|
2017-02-06 17:06:02 -08:00
|
|
|
|
2017-02-13 13:34:30 -08:00
|
|
|
var name obj.AddrName
|
2017-03-06 07:32:37 -08:00
|
|
|
var abbrev int
|
|
|
|
|
offs := n.Xoffset
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
switch n.Class {
|
2016-10-03 12:26:25 -07:00
|
|
|
case PAUTO:
|
2017-02-27 19:56:38 +02:00
|
|
|
if !n.Used() {
|
2016-10-03 12:26:25 -07:00
|
|
|
continue
|
|
|
|
|
}
|
2017-02-06 17:06:02 -08:00
|
|
|
name = obj.NAME_AUTO
|
2017-03-06 07:32:37 -08:00
|
|
|
|
|
|
|
|
abbrev = dwarf.DW_ABRV_AUTO
|
|
|
|
|
if Ctxt.FixedFrameSize() == 0 {
|
|
|
|
|
offs -= int64(Widthptr)
|
|
|
|
|
}
|
|
|
|
|
if obj.Framepointer_enabled(obj.GOOS, obj.GOARCH) {
|
|
|
|
|
offs -= int64(Widthptr)
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-03 12:26:25 -07:00
|
|
|
case PPARAM, PPARAMOUT:
|
2017-02-06 17:06:02 -08:00
|
|
|
name = obj.NAME_PARAM
|
2017-03-06 07:32:37 -08:00
|
|
|
|
|
|
|
|
abbrev = dwarf.DW_ABRV_PARAM
|
|
|
|
|
offs += Ctxt.FixedFrameSize()
|
|
|
|
|
|
2017-02-06 17:06:02 -08:00
|
|
|
default:
|
|
|
|
|
continue
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-03-06 07:32:37 -08:00
|
|
|
gotype := Linksym(ngotype(n))
|
|
|
|
|
fnsym.Autom = append(fnsym.Autom, &obj.Auto{
|
2017-02-06 17:06:02 -08:00
|
|
|
Asym: obj.Linklookup(Ctxt, n.Sym.Name, 0),
|
|
|
|
|
Aoffset: int32(n.Xoffset),
|
|
|
|
|
Name: name,
|
2017-03-06 07:32:37 -08:00
|
|
|
Gotype: gotype,
|
|
|
|
|
})
|
2017-02-06 17:06:02 -08:00
|
|
|
|
2017-03-07 10:57:55 -08:00
|
|
|
if n.IsAutoTmp() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-06 07:32:37 -08:00
|
|
|
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
|
|
|
|
|
vars = append(vars, &dwarf.Var{
|
|
|
|
|
Name: n.Sym.Name,
|
|
|
|
|
Abbrev: abbrev,
|
|
|
|
|
Offset: int32(offs),
|
|
|
|
|
Type: obj.Linklookup(Ctxt, typename, 0),
|
|
|
|
|
})
|
2017-03-03 16:45:21 -08:00
|
|
|
}
|
2017-03-06 07:32:37 -08:00
|
|
|
|
|
|
|
|
// Stable sort so that ties are broken with declaration order.
|
|
|
|
|
sort.Stable(dwarf.VarsByOffset(vars))
|
|
|
|
|
|
|
|
|
|
return vars
|
2017-03-03 14:27:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fieldtrack adds R_USEFIELD relocations to fnsym to record any
|
|
|
|
|
// struct fields that it used.
|
|
|
|
|
func fieldtrack(fnsym *obj.LSym, tracked map[*Sym]struct{}) {
|
|
|
|
|
if fnsym == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if obj.Fieldtrack_enabled == 0 || len(tracked) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trackSyms := make([]*Sym, 0, len(tracked))
|
|
|
|
|
for sym := range tracked {
|
|
|
|
|
trackSyms = append(trackSyms, sym)
|
|
|
|
|
}
|
|
|
|
|
sort.Sort(symByName(trackSyms))
|
|
|
|
|
for _, sym := range trackSyms {
|
|
|
|
|
r := obj.Addrel(fnsym)
|
|
|
|
|
r.Sym = Linksym(sym)
|
|
|
|
|
r.Type = obj.R_USEFIELD
|
2017-02-06 17:06:02 -08:00
|
|
|
}
|
2016-03-07 22:05:49 -08:00
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
type symByName []*Sym
|
|
|
|
|
|
|
|
|
|
func (a symByName) Len() int { return len(a) }
|
|
|
|
|
func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
|
|
|
|
|
func (a symByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|