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] }