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