github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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/internal/obj" 9 "crypto/md5" 10 "fmt" 11 "strings" 12 ) 13 14 // "Portable" code generation. 15 16 var makefuncdatasym_nsym int32 17 18 func makefuncdatasym(namefmt string, funcdatakind int64) *Sym { 19 var nod Node 20 21 sym := Lookupf(namefmt, makefuncdatasym_nsym) 22 makefuncdatasym_nsym++ 23 pnod := newname(sym) 24 pnod.Class = PEXTERN 25 Nodconst(&nod, Types[TINT32], funcdatakind) 26 Thearch.Gins(obj.AFUNCDATA, &nod, pnod) 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 int) { 87 if n == nil { 88 Fatalf("gvardef nil") 89 } 90 if n.Op != ONAME { 91 Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), n) 92 return 93 } 94 95 switch n.Class { 96 case PAUTO, PPARAM, PPARAMOUT: 97 Thearch.Gins(as, nil, n) 98 } 99 } 100 101 func Gvardef(n *Node) { 102 gvardefx(n, obj.AVARDEF) 103 } 104 105 func gvarkill(n *Node) { 106 gvardefx(n, obj.AVARKILL) 107 } 108 109 func removevardef(firstp *obj.Prog) { 110 for p := firstp; p != nil; p = p.Link { 111 for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL) { 112 p.Link = p.Link.Link 113 } 114 if p.To.Type == obj.TYPE_BRANCH { 115 for p.To.Val.(*obj.Prog) != nil && (p.To.Val.(*obj.Prog).As == obj.AVARDEF || p.To.Val.(*obj.Prog).As == obj.AVARKILL) { 116 p.To.Val = p.To.Val.(*obj.Prog).Link 117 } 118 } 119 } 120 } 121 122 func gcsymdup(s *Sym) { 123 ls := Linksym(s) 124 if len(ls.R) > 0 { 125 Fatalf("cannot rosymdup %s with relocations", ls.Name) 126 } 127 ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P)) 128 ls.Dupok = 1 129 } 130 131 func emitptrargsmap() { 132 if Curfn.Func.Nname.Sym.Name == "_" { 133 return 134 } 135 sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name)) 136 137 nptr := int(Curfn.Type.Argwid / int64(Widthptr)) 138 bv := bvalloc(int32(nptr) * 2) 139 nbitmap := 1 140 if Curfn.Type.Outtuple > 0 { 141 nbitmap = 2 142 } 143 off := duint32(sym, 0, uint32(nbitmap)) 144 off = duint32(sym, off, uint32(bv.n)) 145 var xoffset int64 146 if Curfn.Type.Thistuple > 0 { 147 xoffset = 0 148 onebitwalktype1(getthisx(Curfn.Type), &xoffset, bv) 149 } 150 151 if Curfn.Type.Intuple > 0 { 152 xoffset = 0 153 onebitwalktype1(getinargx(Curfn.Type), &xoffset, bv) 154 } 155 156 for j := 0; int32(j) < bv.n; j += 32 { 157 off = duint32(sym, off, bv.b[j/32]) 158 } 159 if Curfn.Type.Outtuple > 0 { 160 xoffset = 0 161 onebitwalktype1(getoutargx(Curfn.Type), &xoffset, bv) 162 for j := 0; int32(j) < bv.n; j += 32 { 163 off = duint32(sym, off, bv.b[j/32]) 164 } 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 != b.Class { 182 if a.Class == PAUTO { 183 return false 184 } 185 return true 186 } 187 188 if a.Class != PAUTO { 189 if a.Xoffset < b.Xoffset { 190 return true 191 } 192 if a.Xoffset > b.Xoffset { 193 return false 194 } 195 return false 196 } 197 198 if a.Used != b.Used { 199 return a.Used 200 } 201 202 ap := haspointers(a.Type) 203 bp := haspointers(b.Type) 204 if ap != bp { 205 return ap 206 } 207 208 ap = a.Name.Needzero 209 bp = b.Name.Needzero 210 if ap != bp { 211 return ap 212 } 213 214 if a.Type.Width < b.Type.Width { 215 return false 216 } 217 if a.Type.Width > b.Type.Width { 218 return true 219 } 220 221 return a.Sym.Name < b.Sym.Name 222 } 223 224 // stkdelta records the stack offset delta for a node 225 // during the compaction of the stack frame to remove 226 // unused stack slots. 227 var stkdelta = map[*Node]int64{} 228 229 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. 230 func allocauto(ptxt *obj.Prog) { 231 Stksize = 0 232 stkptrsize = 0 233 234 if Curfn.Func.Dcl == nil { 235 return 236 } 237 238 // Mark the PAUTO's unused. 239 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 240 if ll.N.Class == PAUTO { 241 ll.N.Used = false 242 } 243 } 244 245 markautoused(ptxt) 246 247 listsort(&Curfn.Func.Dcl, cmpstackvarlt) 248 249 // Unused autos are at the end, chop 'em off. 250 ll := Curfn.Func.Dcl 251 252 n := ll.N 253 if n.Class == PAUTO && n.Op == ONAME && !n.Used { 254 // No locals used at all 255 Curfn.Func.Dcl = nil 256 257 fixautoused(ptxt) 258 return 259 } 260 261 for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next { 262 n = ll.Next.N 263 if n.Class == PAUTO && n.Op == ONAME && !n.Used { 264 ll.Next = nil 265 Curfn.Func.Dcl.End = ll 266 break 267 } 268 } 269 270 // Reassign stack offsets of the locals that are still there. 271 var w int64 272 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 273 n = ll.N 274 if n.Class != PAUTO || n.Op != ONAME { 275 continue 276 } 277 278 dowidth(n.Type) 279 w = n.Type.Width 280 if w >= Thearch.MAXWIDTH || w < 0 { 281 Fatalf("bad width") 282 } 283 Stksize += w 284 Stksize = Rnd(Stksize, int64(n.Type.Align)) 285 if haspointers(n.Type) { 286 stkptrsize = Stksize 287 } 288 if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' { 289 Stksize = Rnd(Stksize, int64(Widthptr)) 290 } 291 if Stksize >= 1<<31 { 292 setlineno(Curfn) 293 Yyerror("stack frame too large (>2GB)") 294 } 295 296 stkdelta[n] = -Stksize - n.Xoffset 297 } 298 299 Stksize = Rnd(Stksize, int64(Widthreg)) 300 stkptrsize = Rnd(stkptrsize, int64(Widthreg)) 301 302 fixautoused(ptxt) 303 304 // The debug information needs accurate offsets on the symbols. 305 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 306 if ll.N.Class != PAUTO || ll.N.Op != ONAME { 307 continue 308 } 309 ll.N.Xoffset += stkdelta[ll.N] 310 delete(stkdelta, ll.N) 311 } 312 } 313 314 func Cgen_checknil(n *Node) { 315 if Disable_checknil != 0 { 316 return 317 } 318 319 // Ideally we wouldn't see any integer types here, but we do. 320 if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) { 321 Dump("checknil", n) 322 Fatalf("bad checknil") 323 } 324 325 if ((Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL { 326 var reg Node 327 Regalloc(®, Types[Tptr], n) 328 Cgen(n, ®) 329 Thearch.Gins(obj.ACHECKNIL, ®, nil) 330 Regfree(®) 331 return 332 } 333 334 Thearch.Gins(obj.ACHECKNIL, n, nil) 335 } 336 337 func compile(fn *Node) { 338 if Newproc == nil { 339 Newproc = Sysfunc("newproc") 340 Deferproc = Sysfunc("deferproc") 341 Deferreturn = Sysfunc("deferreturn") 342 Panicindex = Sysfunc("panicindex") 343 panicslice = Sysfunc("panicslice") 344 throwreturn = Sysfunc("throwreturn") 345 } 346 347 lno := setlineno(fn) 348 349 Curfn = fn 350 dowidth(Curfn.Type) 351 352 var oldstksize int64 353 var nod1 Node 354 var ptxt *obj.Prog 355 var pl *obj.Plist 356 var p *obj.Prog 357 var n *Node 358 var nam *Node 359 var gcargs *Sym 360 var gclocals *Sym 361 if fn.Nbody == nil { 362 if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") { 363 Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name) 364 goto ret 365 } 366 367 if Debug['A'] != 0 { 368 goto ret 369 } 370 emitptrargsmap() 371 goto ret 372 } 373 374 saveerrors() 375 376 // set up domain for labels 377 clearlabels() 378 379 if Curfn.Type.Outnamed { 380 // add clearing of the output parameters 381 var save Iter 382 t := Structfirst(&save, Getoutarg(Curfn.Type)) 383 384 for t != nil { 385 if t.Nname != nil { 386 n = Nod(OAS, t.Nname, nil) 387 typecheck(&n, Etop) 388 Curfn.Nbody = concat(list1(n), Curfn.Nbody) 389 } 390 391 t = structnext(&save) 392 } 393 } 394 395 order(Curfn) 396 if nerrors != 0 { 397 goto ret 398 } 399 400 hasdefer = false 401 walk(Curfn) 402 if nerrors != 0 { 403 goto ret 404 } 405 if instrumenting { 406 instrument(Curfn) 407 } 408 if nerrors != 0 { 409 goto ret 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 Nodconst(&nod1, Types[TINT32], 0) 421 nam = Curfn.Func.Nname 422 if isblank(nam) { 423 nam = nil 424 } 425 ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1) 426 Afunclit(&ptxt.From, Curfn.Func.Nname) 427 ptxt.From3 = new(obj.Addr) 428 if fn.Func.Dupok { 429 ptxt.From3.Offset |= obj.DUPOK 430 } 431 if fn.Func.Wrapper { 432 ptxt.From3.Offset |= obj.WRAPPER 433 } 434 if fn.Func.Needctxt { 435 ptxt.From3.Offset |= obj.NEEDCTXT 436 } 437 if fn.Func.Nosplit { 438 ptxt.From3.Offset |= obj.NOSPLIT 439 } 440 if fn.Func.Systemstack { 441 ptxt.From.Sym.Cfunc = 1 442 } 443 444 // Clumsy but important. 445 // See test/recover.go for test cases and src/reflect/value.go 446 // for the actual functions being considered. 447 if myimportpath != "" && myimportpath == "reflect" { 448 if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" { 449 ptxt.From3.Offset |= obj.WRAPPER 450 } 451 } 452 453 ginit() 454 455 gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps) 456 gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps) 457 458 for _, t := range Curfn.Func.Fieldtrack { 459 gtrack(tracksym(t)) 460 } 461 462 for l := fn.Func.Dcl; l != nil; l = l.Next { 463 n = l.N 464 if n.Op != ONAME { // might be OTYPE or OLITERAL 465 continue 466 } 467 switch n.Class { 468 case PAUTO, PPARAM, PPARAMOUT: 469 Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width) 470 p = Thearch.Gins(obj.ATYPE, l.N, &nod1) 471 p.From.Gotype = Linksym(ngotype(l.N)) 472 } 473 } 474 475 Genlist(Curfn.Func.Enter) 476 Genlist(Curfn.Nbody) 477 gclean() 478 checklabels() 479 if nerrors != 0 { 480 goto ret 481 } 482 if Curfn.Func.Endlineno != 0 { 483 lineno = Curfn.Func.Endlineno 484 } 485 486 if Curfn.Type.Outtuple != 0 { 487 Ginscall(throwreturn, 0) 488 } 489 490 ginit() 491 492 // TODO: Determine when the final cgen_ret can be omitted. Perhaps always? 493 cgen_ret(nil) 494 495 if hasdefer { 496 // deferreturn pretends to have one uintptr argument. 497 // Reserve space for it so stack scanner is happy. 498 if Maxarg < int64(Widthptr) { 499 Maxarg = int64(Widthptr) 500 } 501 } 502 503 gclean() 504 if nerrors != 0 { 505 goto ret 506 } 507 508 Pc.As = obj.ARET // overwrite AEND 509 Pc.Lineno = lineno 510 511 fixjmp(ptxt) 512 if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 { 513 regopt(ptxt) 514 nilopt(ptxt) 515 } 516 517 Thearch.Expandchecks(ptxt) 518 519 oldstksize = Stksize 520 allocauto(ptxt) 521 522 if false { 523 fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize)) 524 } 525 526 setlineno(Curfn) 527 if int64(Stksize)+Maxarg > 1<<31 { 528 Yyerror("stack frame too large (>2GB)") 529 goto ret 530 } 531 532 // Emit garbage collection symbols. 533 liveness(Curfn, ptxt, gcargs, gclocals) 534 535 gcsymdup(gcargs) 536 gcsymdup(gclocals) 537 538 Thearch.Defframe(ptxt) 539 540 if Debug['f'] != 0 { 541 frame(0) 542 } 543 544 // Remove leftover instrumentation from the instruction stream. 545 removevardef(ptxt) 546 547 ret: 548 lineno = lno 549 }