github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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 "crypto/md5" 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 var nod Node 22 23 sym := LookupN(nameprefix, makefuncdatasym_nsym) 24 makefuncdatasym_nsym++ 25 pnod := newname(sym) 26 pnod.Class = PEXTERN 27 Nodconst(&nod, Types[TINT32], funcdatakind) 28 Thearch.Gins(obj.AFUNCDATA, &nod, pnod) 29 return sym 30 } 31 32 // gvardef inserts a VARDEF for n into the instruction stream. 33 // VARDEF is an annotation for the liveness analysis, marking a place 34 // where a complete initialization (definition) of a variable begins. 35 // Since the liveness analysis can see initialization of single-word 36 // variables quite easy, gvardef is usually only called for multi-word 37 // or 'fat' variables, those satisfying isfat(n->type). 38 // However, gvardef is also called when a non-fat variable is initialized 39 // via a block move; the only time this happens is when you have 40 // return f() 41 // for a function with multiple return values exactly matching the return 42 // types of the current function. 43 // 44 // A 'VARDEF x' annotation in the instruction stream tells the liveness 45 // analysis to behave as though the variable x is being initialized at that 46 // point in the instruction stream. The VARDEF must appear before the 47 // actual (multi-instruction) initialization, and it must also appear after 48 // any uses of the previous value, if any. For example, if compiling: 49 // 50 // x = x[1:] 51 // 52 // it is important to generate code like: 53 // 54 // base, len, cap = pieces of x[1:] 55 // VARDEF x 56 // x = {base, len, cap} 57 // 58 // If instead the generated code looked like: 59 // 60 // VARDEF x 61 // base, len, cap = pieces of x[1:] 62 // x = {base, len, cap} 63 // 64 // then the liveness analysis would decide the previous value of x was 65 // unnecessary even though it is about to be used by the x[1:] computation. 66 // Similarly, if the generated code looked like: 67 // 68 // base, len, cap = pieces of x[1:] 69 // x = {base, len, cap} 70 // VARDEF x 71 // 72 // then the liveness analysis will not preserve the new value of x, because 73 // the VARDEF appears to have "overwritten" it. 74 // 75 // VARDEF is a bit of a kludge to work around the fact that the instruction 76 // stream is working on single-word values but the liveness analysis 77 // wants to work on individual variables, which might be multi-word 78 // aggregates. It might make sense at some point to look into letting 79 // the liveness analysis work on single-word values as well, although 80 // there are complications around interface values, slices, and strings, 81 // all of which cannot be treated as individual words. 82 // 83 // VARKILL is the opposite of VARDEF: it marks a value as no longer needed, 84 // even if its address has been taken. That is, a VARKILL annotation asserts 85 // that its argument is certainly dead, for use when the liveness analysis 86 // would not otherwise be able to deduce that fact. 87 88 func gvardefx(n *Node, as obj.As) { 89 if n == nil { 90 Fatalf("gvardef nil") 91 } 92 if n.Op != ONAME { 93 Yyerror("gvardef %v; %v", Oconv(n.Op, FmtSharp), n) 94 return 95 } 96 97 switch n.Class { 98 case PAUTO, PPARAM, PPARAMOUT: 99 if as == obj.AVARLIVE { 100 Thearch.Gins(as, n, nil) 101 } else { 102 Thearch.Gins(as, nil, n) 103 } 104 } 105 } 106 107 func Gvardef(n *Node) { 108 gvardefx(n, obj.AVARDEF) 109 } 110 111 func Gvarkill(n *Node) { 112 gvardefx(n, obj.AVARKILL) 113 } 114 115 func Gvarlive(n *Node) { 116 gvardefx(n, obj.AVARLIVE) 117 } 118 119 func removevardef(firstp *obj.Prog) { 120 for p := firstp; p != nil; p = p.Link { 121 for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL || p.Link.As == obj.AVARLIVE) { 122 p.Link = p.Link.Link 123 } 124 if p.To.Type == obj.TYPE_BRANCH { 125 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) { 126 p.To.Val = p.To.Val.(*obj.Prog).Link 127 } 128 } 129 } 130 } 131 132 func gcsymdup(s *Sym) { 133 ls := Linksym(s) 134 if len(ls.R) > 0 { 135 Fatalf("cannot rosymdup %s with relocations", ls.Name) 136 } 137 ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P)) 138 ls.Dupok = true 139 } 140 141 func emitptrargsmap() { 142 if Curfn.Func.Nname.Sym.Name == "_" { 143 return 144 } 145 sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name)) 146 147 nptr := int(Curfn.Type.ArgWidth() / int64(Widthptr)) 148 bv := bvalloc(int32(nptr) * 2) 149 nbitmap := 1 150 if Curfn.Type.Results().NumFields() > 0 { 151 nbitmap = 2 152 } 153 off := duint32(sym, 0, uint32(nbitmap)) 154 off = duint32(sym, off, uint32(bv.n)) 155 var xoffset int64 156 if Curfn.Type.Recv() != nil { 157 xoffset = 0 158 onebitwalktype1(Curfn.Type.Recvs(), &xoffset, bv) 159 } 160 161 if Curfn.Type.Params().NumFields() > 0 { 162 xoffset = 0 163 onebitwalktype1(Curfn.Type.Params(), &xoffset, bv) 164 } 165 166 for j := 0; int32(j) < bv.n; j += 32 { 167 off = duint32(sym, off, bv.b[j/32]) 168 } 169 if Curfn.Type.Results().NumFields() > 0 { 170 xoffset = 0 171 onebitwalktype1(Curfn.Type.Results(), &xoffset, bv) 172 for j := 0; int32(j) < bv.n; j += 32 { 173 off = duint32(sym, off, bv.b[j/32]) 174 } 175 } 176 177 ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL) 178 } 179 180 // cmpstackvarlt reports whether the stack variable a sorts before b. 181 // 182 // Sort the list of stack variables. Autos after anything else, 183 // within autos, unused after used, within used, things with 184 // pointers first, zeroed things first, and then decreasing size. 185 // Because autos are laid out in decreasing addresses 186 // on the stack, pointers first, zeroed things first and decreasing size 187 // really means, in memory, things with pointers needing zeroing at 188 // the top of the stack and increasing in size. 189 // Non-autos sort on offset. 190 func cmpstackvarlt(a, b *Node) bool { 191 if (a.Class == PAUTO) != (b.Class == PAUTO) { 192 return b.Class == PAUTO 193 } 194 195 if a.Class != PAUTO { 196 return a.Xoffset < b.Xoffset 197 } 198 199 if a.Used != b.Used { 200 return a.Used 201 } 202 203 ap := haspointers(a.Type) 204 bp := haspointers(b.Type) 205 if ap != bp { 206 return ap 207 } 208 209 ap = a.Name.Needzero 210 bp = b.Name.Needzero 211 if ap != bp { 212 return ap 213 } 214 215 if a.Type.Width != b.Type.Width { 216 return a.Type.Width > b.Type.Width 217 } 218 219 return a.Sym.Name < b.Sym.Name 220 } 221 222 // byStackvar implements sort.Interface for []*Node using cmpstackvarlt. 223 type byStackVar []*Node 224 225 func (s byStackVar) Len() int { return len(s) } 226 func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) } 227 func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 228 229 // stkdelta records the stack offset delta for a node 230 // during the compaction of the stack frame to remove 231 // unused stack slots. 232 var stkdelta = map[*Node]int64{} 233 234 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. 235 func allocauto(ptxt *obj.Prog) { 236 Stksize = 0 237 stkptrsize = 0 238 239 if len(Curfn.Func.Dcl) == 0 { 240 return 241 } 242 243 // Mark the PAUTO's unused. 244 for _, ln := range Curfn.Func.Dcl { 245 if ln.Class == PAUTO { 246 ln.Used = false 247 } 248 } 249 250 markautoused(ptxt) 251 252 sort.Sort(byStackVar(Curfn.Func.Dcl)) 253 254 // Unused autos are at the end, chop 'em off. 255 n := Curfn.Func.Dcl[0] 256 if n.Class == PAUTO && n.Op == ONAME && !n.Used { 257 // No locals used at all 258 Curfn.Func.Dcl = nil 259 260 fixautoused(ptxt) 261 return 262 } 263 264 for i := 1; i < len(Curfn.Func.Dcl); i++ { 265 n = Curfn.Func.Dcl[i] 266 if n.Class == PAUTO && n.Op == ONAME && !n.Used { 267 Curfn.Func.Dcl = Curfn.Func.Dcl[:i] 268 break 269 } 270 } 271 272 // Reassign stack offsets of the locals that are still there. 273 var w int64 274 for _, n := range Curfn.Func.Dcl { 275 if n.Class != PAUTO || n.Op != ONAME { 276 continue 277 } 278 279 dowidth(n.Type) 280 w = n.Type.Width 281 if w >= Thearch.MAXWIDTH || w < 0 { 282 Fatalf("bad width") 283 } 284 Stksize += w 285 Stksize = Rnd(Stksize, int64(n.Type.Align)) 286 if haspointers(n.Type) { 287 stkptrsize = Stksize 288 } 289 if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' { 290 Stksize = Rnd(Stksize, int64(Widthptr)) 291 } 292 if Stksize >= 1<<31 { 293 setlineno(Curfn) 294 Yyerror("stack frame too large (>2GB)") 295 } 296 297 stkdelta[n] = -Stksize - n.Xoffset 298 } 299 300 Stksize = Rnd(Stksize, int64(Widthreg)) 301 stkptrsize = Rnd(stkptrsize, int64(Widthreg)) 302 303 fixautoused(ptxt) 304 305 // The debug information needs accurate offsets on the symbols. 306 for _, ln := range Curfn.Func.Dcl { 307 if ln.Class != PAUTO || ln.Op != ONAME { 308 continue 309 } 310 ln.Xoffset += stkdelta[ln] 311 delete(stkdelta, ln) 312 } 313 } 314 315 func Cgen_checknil(n *Node) { 316 if Disable_checknil != 0 { 317 return 318 } 319 320 // Ideally we wouldn't see any integer types here, but we do. 321 if n.Type == nil || (!n.Type.IsPtr() && !n.Type.IsInteger() && n.Type.Etype != TUNSAFEPTR) { 322 Dump("checknil", n) 323 Fatalf("bad checknil") 324 } 325 326 if ((Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL { 327 var reg Node 328 Regalloc(®, Types[Tptr], n) 329 Cgen(n, ®) 330 Thearch.Gins(obj.ACHECKNIL, ®, nil) 331 Regfree(®) 332 return 333 } 334 335 Thearch.Gins(obj.ACHECKNIL, n, nil) 336 } 337 338 func compile(fn *Node) { 339 if Newproc == nil { 340 Newproc = Sysfunc("newproc") 341 Deferproc = Sysfunc("deferproc") 342 Deferreturn = Sysfunc("deferreturn") 343 Panicindex = Sysfunc("panicindex") 344 panicslice = Sysfunc("panicslice") 345 panicdivide = Sysfunc("panicdivide") 346 throwreturn = Sysfunc("throwreturn") 347 growslice = Sysfunc("growslice") 348 writebarrierptr = Sysfunc("writebarrierptr") 349 typedmemmove = Sysfunc("typedmemmove") 350 panicdottype = Sysfunc("panicdottype") 351 } 352 353 defer func(lno int32) { 354 lineno = lno 355 }(setlineno(fn)) 356 357 Curfn = fn 358 dowidth(Curfn.Type) 359 360 if len(fn.Nbody.Slice()) == 0 { 361 if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") { 362 Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name) 363 return 364 } 365 366 if Debug['A'] != 0 { 367 return 368 } 369 emitptrargsmap() 370 return 371 } 372 373 saveerrors() 374 375 // set up domain for labels 376 clearlabels() 377 378 if Curfn.Type.Outnamed { 379 // add clearing of the output parameters 380 for _, t := range Curfn.Type.Results().Fields().Slice() { 381 if t.Nname != nil { 382 n := Nod(OAS, t.Nname, nil) 383 n = typecheck(n, Etop) 384 Curfn.Nbody.Set(append([]*Node{n}, Curfn.Nbody.Slice()...)) 385 } 386 } 387 } 388 389 order(Curfn) 390 if nerrors != 0 { 391 return 392 } 393 394 hasdefer = false 395 walk(Curfn) 396 if nerrors != 0 { 397 return 398 } 399 if instrumenting { 400 instrument(Curfn) 401 } 402 if nerrors != 0 { 403 return 404 } 405 406 // Build an SSA backend function. 407 var ssafn *ssa.Func 408 if shouldssa(Curfn) { 409 ssafn = buildssa(Curfn) 410 } 411 412 continpc = nil 413 breakpc = nil 414 415 pl := newplist() 416 pl.Name = Linksym(Curfn.Func.Nname.Sym) 417 418 setlineno(Curfn) 419 420 var nod1 Node 421 Nodconst(&nod1, Types[TINT32], 0) 422 nam := Curfn.Func.Nname 423 if isblank(nam) { 424 nam = nil 425 } 426 ptxt := Thearch.Gins(obj.ATEXT, nam, &nod1) 427 Afunclit(&ptxt.From, Curfn.Func.Nname) 428 ptxt.From3 = new(obj.Addr) 429 if fn.Func.Dupok { 430 ptxt.From3.Offset |= obj.DUPOK 431 } 432 if fn.Func.Wrapper { 433 ptxt.From3.Offset |= obj.WRAPPER 434 } 435 if fn.Func.Needctxt { 436 ptxt.From3.Offset |= obj.NEEDCTXT 437 } 438 if fn.Func.Pragma&Nosplit != 0 { 439 ptxt.From3.Offset |= obj.NOSPLIT 440 } 441 if fn.Func.ReflectMethod { 442 ptxt.From3.Offset |= obj.REFLECTMETHOD 443 } 444 if fn.Func.Pragma&Systemstack != 0 { 445 ptxt.From.Sym.Cfunc = true 446 } 447 448 // Clumsy but important. 449 // See test/recover.go for test cases and src/reflect/value.go 450 // for the actual functions being considered. 451 if myimportpath == "reflect" { 452 if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" { 453 ptxt.From3.Offset |= obj.WRAPPER 454 } 455 } 456 457 ginit() 458 459 gcargs := makefuncdatasym("gcargs·", obj.FUNCDATA_ArgsPointerMaps) 460 gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps) 461 462 if obj.Fieldtrack_enabled != 0 && len(Curfn.Func.FieldTrack) > 0 { 463 trackSyms := make([]*Sym, 0, len(Curfn.Func.FieldTrack)) 464 for sym := range Curfn.Func.FieldTrack { 465 trackSyms = append(trackSyms, sym) 466 } 467 sort.Sort(symByName(trackSyms)) 468 for _, sym := range trackSyms { 469 gtrack(sym) 470 } 471 } 472 473 for _, n := range fn.Func.Dcl { 474 if n.Op != ONAME { // might be OTYPE or OLITERAL 475 continue 476 } 477 switch n.Class { 478 case PAUTO, PPARAM, PPARAMOUT: 479 Nodconst(&nod1, Types[TUINTPTR], n.Type.Width) 480 p := Thearch.Gins(obj.ATYPE, n, &nod1) 481 p.From.Gotype = Linksym(ngotype(n)) 482 } 483 } 484 485 if ssafn != nil { 486 genssa(ssafn, ptxt, gcargs, gclocals) 487 ssafn.Free() 488 } else { 489 genlegacy(ptxt, gcargs, gclocals) 490 } 491 } 492 493 type symByName []*Sym 494 495 func (a symByName) Len() int { return len(a) } 496 func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name } 497 func (a symByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 498 499 // genlegacy compiles Curfn using the legacy non-SSA code generator. 500 func genlegacy(ptxt *obj.Prog, gcargs, gclocals *Sym) { 501 Genlist(Curfn.Func.Enter) 502 Genlist(Curfn.Nbody) 503 gclean() 504 checklabels() 505 if nerrors != 0 { 506 return 507 } 508 if Curfn.Func.Endlineno != 0 { 509 lineno = Curfn.Func.Endlineno 510 } 511 512 if Curfn.Type.Results().NumFields() != 0 { 513 Ginscall(throwreturn, 0) 514 } 515 516 ginit() 517 518 // TODO: Determine when the final cgen_ret can be omitted. Perhaps always? 519 cgen_ret(nil) 520 521 if hasdefer { 522 // deferreturn pretends to have one uintptr argument. 523 // Reserve space for it so stack scanner is happy. 524 if Maxarg < int64(Widthptr) { 525 Maxarg = int64(Widthptr) 526 } 527 } 528 529 gclean() 530 if nerrors != 0 { 531 return 532 } 533 534 Pc.As = obj.ARET // overwrite AEND 535 Pc.Lineno = lineno 536 537 fixjmp(ptxt) 538 if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 { 539 regopt(ptxt) 540 nilopt(ptxt) 541 } 542 543 Thearch.Expandchecks(ptxt) 544 545 allocauto(ptxt) 546 547 setlineno(Curfn) 548 if Stksize+Maxarg > 1<<31 { 549 Yyerror("stack frame too large (>2GB)") 550 return 551 } 552 553 // Emit garbage collection symbols. 554 liveness(Curfn, ptxt, gcargs, gclocals) 555 556 gcsymdup(gcargs) 557 gcsymdup(gclocals) 558 559 Thearch.Defframe(ptxt) 560 561 if Debug['f'] != 0 { 562 frame(0) 563 } 564 565 // Remove leftover instrumentation from the instruction stream. 566 removevardef(ptxt) 567 }