github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/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 Fatal("gvardef nil") 89 } 90 if n.Op != ONAME { 91 Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), Nconv(n, 0)) 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 Fatal("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 sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Nname.Sym.Name)) 133 134 nptr := int(Curfn.Type.Argwid / int64(Widthptr)) 135 bv := bvalloc(int32(nptr) * 2) 136 nbitmap := 1 137 if Curfn.Type.Outtuple > 0 { 138 nbitmap = 2 139 } 140 off := duint32(sym, 0, uint32(nbitmap)) 141 off = duint32(sym, off, uint32(bv.n)) 142 var xoffset int64 143 if Curfn.Type.Thistuple > 0 { 144 xoffset = 0 145 twobitwalktype1(getthisx(Curfn.Type), &xoffset, bv) 146 } 147 148 if Curfn.Type.Intuple > 0 { 149 xoffset = 0 150 twobitwalktype1(getinargx(Curfn.Type), &xoffset, bv) 151 } 152 153 for j := 0; int32(j) < bv.n; j += 32 { 154 off = duint32(sym, off, bv.b[j/32]) 155 } 156 if Curfn.Type.Outtuple > 0 { 157 xoffset = 0 158 twobitwalktype1(getoutargx(Curfn.Type), &xoffset, bv) 159 for j := 0; int32(j) < bv.n; j += 32 { 160 off = duint32(sym, off, bv.b[j/32]) 161 } 162 } 163 164 ggloblsym(sym, int32(off), obj.RODATA) 165 } 166 167 // Sort the list of stack variables. Autos after anything else, 168 // within autos, unused after used, within used, things with 169 // pointers first, zeroed things first, and then decreasing size. 170 // Because autos are laid out in decreasing addresses 171 // on the stack, pointers first, zeroed things first and decreasing size 172 // really means, in memory, things with pointers needing zeroing at 173 // the top of the stack and increasing in size. 174 // Non-autos sort on offset. 175 func cmpstackvar(a *Node, b *Node) int { 176 if a.Class != b.Class { 177 if a.Class == PAUTO { 178 return +1 179 } 180 return -1 181 } 182 183 if a.Class != PAUTO { 184 if a.Xoffset < b.Xoffset { 185 return -1 186 } 187 if a.Xoffset > b.Xoffset { 188 return +1 189 } 190 return 0 191 } 192 193 if a.Used != b.Used { 194 return bool2int(b.Used) - bool2int(a.Used) 195 } 196 197 ap := bool2int(haspointers(a.Type)) 198 bp := bool2int(haspointers(b.Type)) 199 if ap != bp { 200 return bp - ap 201 } 202 203 ap = bool2int(a.Needzero) 204 bp = bool2int(b.Needzero) 205 if ap != bp { 206 return bp - ap 207 } 208 209 if a.Type.Width < b.Type.Width { 210 return +1 211 } 212 if a.Type.Width > b.Type.Width { 213 return -1 214 } 215 216 return stringsCompare(a.Sym.Name, b.Sym.Name) 217 } 218 219 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. 220 func allocauto(ptxt *obj.Prog) { 221 Stksize = 0 222 stkptrsize = 0 223 224 if Curfn.Func.Dcl == nil { 225 return 226 } 227 228 // Mark the PAUTO's unused. 229 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 230 if ll.N.Class == PAUTO { 231 ll.N.Used = false 232 } 233 } 234 235 markautoused(ptxt) 236 237 listsort(&Curfn.Func.Dcl, cmpstackvar) 238 239 // Unused autos are at the end, chop 'em off. 240 ll := Curfn.Func.Dcl 241 242 n := ll.N 243 if n.Class == PAUTO && n.Op == ONAME && !n.Used { 244 // No locals used at all 245 Curfn.Func.Dcl = nil 246 247 fixautoused(ptxt) 248 return 249 } 250 251 for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next { 252 n = ll.Next.N 253 if n.Class == PAUTO && n.Op == ONAME && !n.Used { 254 ll.Next = nil 255 Curfn.Func.Dcl.End = ll 256 break 257 } 258 } 259 260 // Reassign stack offsets of the locals that are still there. 261 var w int64 262 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 263 n = ll.N 264 if n.Class != PAUTO || n.Op != ONAME { 265 continue 266 } 267 268 dowidth(n.Type) 269 w = n.Type.Width 270 if w >= Thearch.MAXWIDTH || w < 0 { 271 Fatal("bad width") 272 } 273 Stksize += w 274 Stksize = Rnd(Stksize, int64(n.Type.Align)) 275 if haspointers(n.Type) { 276 stkptrsize = Stksize 277 } 278 if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' { 279 Stksize = Rnd(Stksize, int64(Widthptr)) 280 } 281 if Stksize >= 1<<31 { 282 setlineno(Curfn) 283 Yyerror("stack frame too large (>2GB)") 284 } 285 286 n.Stkdelta = -Stksize - n.Xoffset 287 } 288 289 Stksize = Rnd(Stksize, int64(Widthreg)) 290 stkptrsize = Rnd(stkptrsize, int64(Widthreg)) 291 292 fixautoused(ptxt) 293 294 // The debug information needs accurate offsets on the symbols. 295 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 296 if ll.N.Class != PAUTO || ll.N.Op != ONAME { 297 continue 298 } 299 ll.N.Xoffset += ll.N.Stkdelta 300 ll.N.Stkdelta = 0 301 } 302 } 303 304 func movelarge(l *NodeList) { 305 for ; l != nil; l = l.Next { 306 if l.N.Op == ODCLFUNC { 307 movelargefn(l.N) 308 } 309 } 310 } 311 312 func movelargefn(fn *Node) { 313 var n *Node 314 315 for l := fn.Func.Dcl; l != nil; l = l.Next { 316 n = l.N 317 if n.Class == PAUTO && n.Type != nil && n.Type.Width > MaxStackVarSize { 318 addrescapes(n) 319 } 320 } 321 } 322 323 func Cgen_checknil(n *Node) { 324 if Disable_checknil != 0 { 325 return 326 } 327 328 // Ideally we wouldn't see any integer types here, but we do. 329 if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) { 330 Dump("checknil", n) 331 Fatal("bad checknil") 332 } 333 334 if ((Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL { 335 var reg Node 336 Regalloc(®, Types[Tptr], n) 337 Cgen(n, ®) 338 Thearch.Gins(obj.ACHECKNIL, ®, nil) 339 Regfree(®) 340 return 341 } 342 343 Thearch.Gins(obj.ACHECKNIL, n, nil) 344 } 345 346 func compile(fn *Node) { 347 if Newproc == nil { 348 Newproc = Sysfunc("newproc") 349 Deferproc = Sysfunc("deferproc") 350 Deferreturn = Sysfunc("deferreturn") 351 Panicindex = Sysfunc("panicindex") 352 panicslice = Sysfunc("panicslice") 353 throwreturn = Sysfunc("throwreturn") 354 } 355 356 lno := setlineno(fn) 357 358 Curfn = fn 359 dowidth(Curfn.Type) 360 361 var oldstksize int64 362 var nod1 Node 363 var ptxt *obj.Prog 364 var pl *obj.Plist 365 var p *obj.Prog 366 var n *Node 367 var nam *Node 368 var gcargs *Sym 369 var gclocals *Sym 370 if fn.Nbody == nil { 371 if pure_go != 0 || strings.HasPrefix(fn.Nname.Sym.Name, "init.") { 372 Yyerror("missing function body for %q", fn.Nname.Sym.Name) 373 goto ret 374 } 375 376 if Debug['A'] != 0 { 377 goto ret 378 } 379 emitptrargsmap() 380 goto ret 381 } 382 383 saveerrors() 384 385 // set up domain for labels 386 clearlabels() 387 388 if Curfn.Type.Outnamed != 0 { 389 // add clearing of the output parameters 390 var save Iter 391 t := Structfirst(&save, Getoutarg(Curfn.Type)) 392 393 for t != nil { 394 if t.Nname != nil { 395 n = Nod(OAS, t.Nname, nil) 396 typecheck(&n, Etop) 397 Curfn.Nbody = concat(list1(n), Curfn.Nbody) 398 } 399 400 t = structnext(&save) 401 } 402 } 403 404 order(Curfn) 405 if nerrors != 0 { 406 goto ret 407 } 408 409 Hasdefer = 0 410 walk(Curfn) 411 if nerrors != 0 { 412 goto ret 413 } 414 if flag_race != 0 { 415 racewalk(Curfn) 416 } 417 if nerrors != 0 { 418 goto ret 419 } 420 421 continpc = nil 422 breakpc = nil 423 424 pl = newplist() 425 pl.Name = Linksym(Curfn.Nname.Sym) 426 427 setlineno(Curfn) 428 429 Nodconst(&nod1, Types[TINT32], 0) 430 nam = Curfn.Nname 431 if isblank(nam) { 432 nam = nil 433 } 434 ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1) 435 if fn.Func.Dupok { 436 ptxt.From3.Offset |= obj.DUPOK 437 } 438 if fn.Func.Wrapper { 439 ptxt.From3.Offset |= obj.WRAPPER 440 } 441 if fn.Func.Needctxt { 442 ptxt.From3.Offset |= obj.NEEDCTXT 443 } 444 if fn.Func.Nosplit { 445 ptxt.From3.Offset |= obj.NOSPLIT 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 != "" && myimportpath == "reflect" { 452 if Curfn.Nname.Sym.Name == "callReflect" || Curfn.Nname.Sym.Name == "callMethod" { 453 ptxt.From3.Offset |= obj.WRAPPER 454 } 455 } 456 457 Afunclit(&ptxt.From, Curfn.Nname) 458 459 ginit() 460 461 gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps) 462 gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps) 463 464 for t := Curfn.Paramfld; t != nil; t = t.Down { 465 gtrack(tracksym(t.Type)) 466 } 467 468 for l := fn.Func.Dcl; l != nil; l = l.Next { 469 n = l.N 470 if n.Op != ONAME { // might be OTYPE or OLITERAL 471 continue 472 } 473 switch n.Class { 474 case PAUTO, PPARAM, PPARAMOUT: 475 Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width) 476 p = Thearch.Gins(obj.ATYPE, l.N, &nod1) 477 p.From.Gotype = Linksym(ngotype(l.N)) 478 } 479 } 480 481 Genlist(Curfn.Func.Enter) 482 Genlist(Curfn.Nbody) 483 gclean() 484 checklabels() 485 if nerrors != 0 { 486 goto ret 487 } 488 if Curfn.Func.Endlineno != 0 { 489 lineno = Curfn.Func.Endlineno 490 } 491 492 if Curfn.Type.Outtuple != 0 { 493 Ginscall(throwreturn, 0) 494 } 495 496 ginit() 497 498 // TODO: Determine when the final cgen_ret can be omitted. Perhaps always? 499 cgen_ret(nil) 500 501 if Hasdefer != 0 { 502 // deferreturn pretends to have one uintptr argument. 503 // Reserve space for it so stack scanner is happy. 504 if Maxarg < int64(Widthptr) { 505 Maxarg = int64(Widthptr) 506 } 507 } 508 509 gclean() 510 if nerrors != 0 { 511 goto ret 512 } 513 514 Pc.As = obj.ARET // overwrite AEND 515 Pc.Lineno = lineno 516 517 fixjmp(ptxt) 518 if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 { 519 regopt(ptxt) 520 nilopt(ptxt) 521 } 522 523 Thearch.Expandchecks(ptxt) 524 525 oldstksize = Stksize 526 allocauto(ptxt) 527 528 if false { 529 fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize)) 530 } 531 532 setlineno(Curfn) 533 if int64(Stksize)+Maxarg > 1<<31 { 534 Yyerror("stack frame too large (>2GB)") 535 goto ret 536 } 537 538 // Emit garbage collection symbols. 539 liveness(Curfn, ptxt, gcargs, gclocals) 540 541 gcsymdup(gcargs) 542 gcsymdup(gclocals) 543 544 Thearch.Defframe(ptxt) 545 546 if Debug['f'] != 0 { 547 frame(0) 548 } 549 550 // Remove leftover instrumentation from the instruction stream. 551 removevardef(ptxt) 552 553 ret: 554 lineno = lno 555 }